com.liferay.source.formatter.check.MarkdownSourceFormatterReadmeCheck Maven / Gradle / Ivy
The newest version!
/**
* SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
* SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
*/
package com.liferay.source.formatter.check;
import com.liferay.petra.string.CharPool;
import com.liferay.petra.string.StringBundler;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.ListUtil;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.source.formatter.check.util.SourceUtil;
import com.liferay.source.formatter.parser.JavaClass;
import com.liferay.source.formatter.parser.JavaClassParser;
import com.liferay.source.formatter.util.CheckType;
import com.liferay.source.formatter.util.FileUtil;
import com.liferay.source.formatter.util.SourceFormatterUtil;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
/**
* @author Hugo Huijser
*/
public class MarkdownSourceFormatterReadmeCheck extends BaseFileCheck {
@Override
protected String doProcess(
String fileName, String absolutePath, String content)
throws IOException {
if (!absolutePath.endsWith("/source-formatter/README.markdown")) {
return content;
}
int x = content.indexOf("\n## Checks\n");
if (x == -1) {
return content;
}
String checksInformation = content.substring(x + 1);
try {
String newChecksInformation = _getChecksInformation(
absolutePath, _getCheckInfoMap());
if (!checksInformation.equals(newChecksInformation)) {
return StringUtil.replaceLast(
content, checksInformation, newChecksInformation);
}
}
catch (DocumentException documentException) {
return content;
}
return content;
}
private Map _addCheckstyleChecks(
Map checkInfoMap, Element moduleElement,
String sourceProcessorName) {
String checkName = moduleElement.attributeValue("name");
if (!checkName.endsWith("Check")) {
for (Element childModuleElement :
(List)moduleElement.elements("module")) {
checkInfoMap = _addCheckstyleChecks(
checkInfoMap, childModuleElement, sourceProcessorName);
}
return checkInfoMap;
}
int x = checkName.lastIndexOf(CharPool.PERIOD);
if (x != -1) {
checkName = checkName.substring(x + 1);
}
CheckInfo checkInfo = checkInfoMap.get(checkName);
if (checkInfo != null) {
checkInfo.addSourceProcessorName(sourceProcessorName);
checkInfoMap.put(checkName, checkInfo);
return checkInfoMap;
}
String category = _getPropertyValue(moduleElement, "category");
if (Validator.isNull(category)) {
category = "Miscellaneous";
}
checkInfoMap.put(
checkName,
new CheckInfo(
checkName, category,
_getPropertyValue(moduleElement, "description"),
_getPropertyValue(moduleElement, "documentationLocation"),
CheckType.CHECKSTYLE, sourceProcessorName));
return checkInfoMap;
}
private Map _addCheckstyleChecks(
Map checkInfoMap,
String configurationFileLocation, String sourceProcessorName)
throws DocumentException, IOException {
String checkstyleConfigurationContent = getContent(
configurationFileLocation, getMaxDirLevel());
Document document = SourceUtil.readXML(checkstyleConfigurationContent);
if (document == null) {
throw new DocumentException();
}
return _addCheckstyleChecks(
checkInfoMap, document.getRootElement(), sourceProcessorName);
}
private Map _addSourceChecks(
Map checkInfoMap,
String configurationFileLocation)
throws DocumentException, IOException {
String sourceChecksConfigurationContent = getContent(
configurationFileLocation, getMaxDirLevel());
Document document = SourceUtil.readXML(
sourceChecksConfigurationContent);
if (document == null) {
throw new DocumentException();
}
Element rootElement = document.getRootElement();
for (Element sourceProcessorElement :
(List)rootElement.elements("source-processor")) {
String sourceProcessorName = sourceProcessorElement.attributeValue(
"name");
for (Element checkElement :
(List)sourceProcessorElement.elements("check")) {
String checkName = checkElement.attributeValue("name");
CheckInfo checkInfo = checkInfoMap.get(checkName);
if (checkInfo != null) {
checkInfo.addSourceProcessorName(sourceProcessorName);
checkInfoMap.put(checkName, checkInfo);
continue;
}
Element categoryElement = checkElement.element("category");
String category = "Miscellaneous";
if (categoryElement != null) {
category = categoryElement.attributeValue("name");
}
Element descriptionElement = checkElement.element(
"description");
String description = StringPool.BLANK;
if (descriptionElement != null) {
description = descriptionElement.attributeValue("name");
}
checkInfoMap.put(
checkName,
new CheckInfo(
checkName, category, description, StringPool.BLANK,
CheckType.SOURCE_CHECK, sourceProcessorName));
}
}
return checkInfoMap;
}
private void _createChecksTableMarkdown(
String header, String rootFolderLocation, File file,
Collection checkInfos, File documentationChecksDir,
boolean displayCategory, boolean displayFileExtensions)
throws IOException {
String content = StringPool.BLANK;
if (file.exists()) {
content = FileUtil.read(file);
}
StringBundler sb = new StringBundler();
sb.append("# ");
sb.append(header);
sb.append("\n\n");
sb.append("Check | ");
if (displayCategory) {
sb.append("Category | ");
}
if (displayFileExtensions) {
sb.append("File Extensions | ");
}
sb.append("Description\n");
sb.append("----- | ");
if (displayCategory) {
sb.append("-------- | ");
}
if (displayFileExtensions) {
sb.append("--------------- | ");
}
sb.append("-----------\n");
for (CheckInfo checkInfo : checkInfos) {
String checkName = checkInfo.getName();
String documentationlink = _getDocumentationLink(
rootFolderLocation, documentationChecksDir, checkInfo);
if (documentationlink != null) {
sb.append("[");
sb.append(checkName);
sb.append("](");
sb.append(documentationlink);
sb.append(") | ");
}
else {
sb.append(checkName);
sb.append(" | ");
}
if (displayCategory) {
String category = checkInfo.getCategory();
if (Validator.isNotNull(category)) {
String categoryWithoutSpace = StringUtil.removeChar(
category, CharPool.SPACE);
sb.append(
_getLink(
SourceFormatterUtil.getMarkdownFileName(
categoryWithoutSpace + "Checks"),
"", category, category + " Checks"));
sb.append(" | ");
}
else {
sb.append("| ");
}
}
if (displayFileExtensions) {
String fileExtensionsString = _getFileExtensionsString(
checkInfo.getSourceProcessorNames());
if (Validator.isNotNull(fileExtensionsString)) {
sb.append(fileExtensionsString);
sb.append(" | ");
}
else {
sb.append("| ");
}
}
if (Validator.isNotNull(checkInfo.getDescription())) {
sb.append(checkInfo.getDescription());
sb.append(" |");
}
else {
sb.append("|");
}
sb.append("\n");
}
String newContent = StringUtil.trim(sb.toString());
if (content.equals(newContent)) {
return;
}
String absolutePath = SourceUtil.getAbsolutePath(file);
if (Validator.isNull(content)) {
System.out.println("Added " + absolutePath);
}
else {
System.out.println("Updated " + absolutePath);
}
FileUtil.write(file, StringUtil.trim(sb.toString()));
}
private Set _getCategories(Map checkInfoMap) {
Set categories = new TreeSet<>();
for (CheckInfo checkInfo : checkInfoMap.values()) {
categories.add(checkInfo.getCategory());
}
return categories;
}
private List _getCategoryCheckInfos(
String category, Map checkInfoMap) {
List checkInfos = new ArrayList<>();
for (CheckInfo checkInfo : checkInfoMap.values()) {
if (category.equals(checkInfo.getCategory())) {
checkInfos.add(checkInfo);
}
}
return checkInfos;
}
private Map _getCheckInfoMap()
throws DocumentException, IOException {
Map checkInfoMap = new TreeMap<>();
String resourcesDirLocation =
"modules/util/source-formatter/src/main/resources/";
checkInfoMap = _addCheckstyleChecks(
checkInfoMap, resourcesDirLocation + "checkstyle.xml",
"JavaSourceProcessor");
checkInfoMap = _addCheckstyleChecks(
checkInfoMap, resourcesDirLocation + "checkstyle-jsp.xml",
"JSPSourceProcessor");
checkInfoMap = _addSourceChecks(
checkInfoMap, resourcesDirLocation + "sourcechecks.xml");
return checkInfoMap;
}
private String _getChecksInformation(
String absolutePath, Map checkInfoMap)
throws DocumentException, IOException {
int x = absolutePath.lastIndexOf(StringPool.SLASH);
String rootFolderLocation = absolutePath.substring(0, x + 1);
File documentationDir = new File(
rootFolderLocation + _DOCUMENTATION_DIR_LOCATION);
File documentationChecksDir = new File(
documentationDir, _DOCUMENTATION_CHECKS_DIR_NAME);
StringBundler sb = new StringBundler();
sb.append("## Checks\n\n");
String headerName = "All Checks";
String markdownFileName = SourceFormatterUtil.getMarkdownFileName(
"AllChecks");
sb.append(
_getLink(
_DOCUMENTATION_DIR_LOCATION + markdownFileName, "- ### ",
headerName, headerName));
sb.append("\n\n");
_createChecksTableMarkdown(
headerName, rootFolderLocation,
new File(documentationDir, markdownFileName), checkInfoMap.values(),
documentationChecksDir, true, true);
sb.append("- ### By Category:\n");
for (String category : _getCategories(checkInfoMap)) {
headerName = category + " Checks";
markdownFileName = SourceFormatterUtil.getMarkdownFileName(
StringUtil.removeChar(category, CharPool.SPACE) + "Checks");
sb.append(
_getLink(
_DOCUMENTATION_DIR_LOCATION + markdownFileName, " - ",
category, headerName));
sb.append("\n");
_createChecksTableMarkdown(
headerName, rootFolderLocation,
new File(documentationDir, markdownFileName),
_getCategoryCheckInfos(category, checkInfoMap),
documentationChecksDir, false, true);
}
sb.append("\n");
sb.append("- ### By File Extensions:\n");
for (String sourceProcessorName :
_getSourceProcessorNames(checkInfoMap)) {
if (sourceProcessorName.equals("all")) {
continue;
}
String fileExtensionsString = _getFileExtensionsString(
ListUtil.fromArray(sourceProcessorName));
headerName = "Checks for " + fileExtensionsString;
markdownFileName = SourceFormatterUtil.getMarkdownFileName(
sourceProcessorName + "Checks");
sb.append(
_getLink(
_DOCUMENTATION_DIR_LOCATION + markdownFileName, " - ",
fileExtensionsString, headerName));
sb.append("\n");
_createChecksTableMarkdown(
"Checks for " + fileExtensionsString, rootFolderLocation,
new File(documentationDir, markdownFileName),
_getSourceProcessorCheckInfos(
sourceProcessorName, checkInfoMap),
documentationChecksDir, true, false);
}
return StringUtil.trim(sb.toString());
}
private String _getDocumentationLink(
File documentationChecksDir, String checkName) {
String markdownFileName = SourceFormatterUtil.getMarkdownFileName(
checkName);
File markdownFile = new File(documentationChecksDir, markdownFileName);
if (markdownFile.exists()) {
return StringBundler.concat(
_DOCUMENTATION_CHECKS_DIR_NAME, markdownFileName, "#",
StringUtil.toLowerCase(checkName));
}
return null;
}
private String _getDocumentationLink(
String rootFolderLocation, File documentationChecksDir,
CheckInfo checkInfo) {
String documentationLocation = checkInfo.getDocumentationLocation();
if (Validator.isNotNull(documentationLocation)) {
return SourceFormatterUtil.CHECKSTYLE_DOCUMENTATION_URL_BASE +
documentationLocation;
}
String checkName = checkInfo.getName();
String documentationLink = _getDocumentationLink(
documentationChecksDir, checkName);
if (documentationLink != null) {
return documentationLink;
}
File sourceDir = null;
CheckType checkType = checkInfo.getCheckType();
if (checkType.equals(CheckType.CHECKSTYLE)) {
sourceDir = new File(
rootFolderLocation + _CHECKSTYLE_SOURCE_LOCATION);
}
else {
sourceDir = new File(
rootFolderLocation + _SOURCE_CHECKS_SOURCE_LOCATION);
}
File sourceFile = new File(sourceDir, checkName + ".java");
if (!sourceFile.exists()) {
return null;
}
JavaClass javaClass = null;
try {
javaClass = JavaClassParser.parseJavaClass(
sourceFile.getName(), FileUtil.read(sourceFile));
}
catch (Exception exception) {
if (_log.isDebugEnabled()) {
_log.debug(exception);
}
return null;
}
List extendedClassNames = javaClass.getExtendedClassNames();
if (extendedClassNames.isEmpty()) {
return null;
}
String extendedClassName = extendedClassNames.get(0);
sourceFile = new File(sourceDir, extendedClassName + ".java");
if (!sourceFile.exists()) {
return null;
}
documentationLink = _getDocumentationLink(
documentationChecksDir, extendedClassName);
if ((documentationLink != null) ||
!extendedClassName.startsWith("Base")) {
return documentationLink;
}
return _getDocumentationLink(
documentationChecksDir, extendedClassName.substring(4));
}
private List _getFileExtensions(String sourceProcessorName) {
List fileExtensions = _sourceProcessorFileExtensionsMap.get(
sourceProcessorName);
if (fileExtensions != null) {
return fileExtensions;
}
fileExtensions = new ArrayList<>();
try {
Class> clazz = Class.forName(
"com.liferay.source.formatter.processor." +
sourceProcessorName);
Field field = clazz.getDeclaredField("_INCLUDES");
field.setAccessible(true);
String[] includes = (String[])field.get(null);
for (String include : includes) {
int x = include.lastIndexOf(CharPool.PERIOD);
int y = include.lastIndexOf(CharPool.SLASH);
if (x < y) {
fileExtensions.add(include.substring(y + 1));
}
else {
fileExtensions.add(include.substring(x));
}
}
}
catch (Exception exception) {
if (_log.isDebugEnabled()) {
_log.debug(exception);
}
}
_sourceProcessorFileExtensionsMap.put(
sourceProcessorName, fileExtensions);
return fileExtensions;
}
private String _getFileExtensionsString(List sourceProcessorNames) {
List fileExtensions = new ArrayList<>();
for (String sourceProcessorName : sourceProcessorNames) {
fileExtensions.addAll(_getFileExtensions(sourceProcessorName));
}
Collections.sort(fileExtensions);
StringBundler sb = new StringBundler();
for (int i = 0; i < fileExtensions.size(); i++) {
sb.append(fileExtensions.get(i));
if (i == (fileExtensions.size() - 2)) {
sb.append(" or ");
}
else if (i < (fileExtensions.size() - 1)) {
sb.append(", ");
}
}
return sb.toString();
}
private String _getLink(
String markdownFileName, String prefix, String linkName,
String headerName) {
StringBundler sb = new StringBundler(8);
sb.append(prefix);
sb.append("[");
sb.append(linkName);
sb.append("](");
sb.append(markdownFileName);
sb.append("#");
String headerLink = headerName.replaceAll("[^ \\w]", StringPool.BLANK);
headerLink = StringUtil.replace(
headerLink, CharPool.SPACE, CharPool.DASH);
sb.append(StringUtil.toLowerCase(headerLink));
sb.append(")");
return sb.toString();
}
private String _getPropertyValue(
Element moduleElement, String propertyName) {
for (Element propertyElement :
(List)moduleElement.elements("property")) {
if (propertyName.equals(propertyElement.attributeValue("name"))) {
return propertyElement.attributeValue("value");
}
}
return StringPool.BLANK;
}
private List _getSourceProcessorCheckInfos(
String sourceProcessorName, Map checkInfoMap) {
List checkInfos = new ArrayList<>();
for (CheckInfo checkInfo : checkInfoMap.values()) {
List sourceProcessorNames =
checkInfo.getSourceProcessorNames();
if (sourceProcessorNames.contains(sourceProcessorName)) {
checkInfos.add(checkInfo);
}
}
return checkInfos;
}
private Set _getSourceProcessorNames(
Map checkInfoMap) {
Set sourceProcessorNames = new TreeSet<>(
(sourceProcessorName1, sourceProcessorName2) -> {
String fileExtensionsString1 = _getFileExtensionsString(
ListUtil.fromArray(sourceProcessorName1));
String fileExtensionsString2 = _getFileExtensionsString(
ListUtil.fromArray(sourceProcessorName2));
return fileExtensionsString1.compareTo(fileExtensionsString2);
});
for (CheckInfo checkInfo : checkInfoMap.values()) {
for (String sourceProcessorName :
checkInfo.getSourceProcessorNames()) {
if (!sourceProcessorName.equals("all")) {
sourceProcessorNames.add(sourceProcessorName);
}
}
}
return sourceProcessorNames;
}
private static final String _CHECKSTYLE_SOURCE_LOCATION =
"src/main/java/com/liferay/source/formatter/checkstyle/check/";
private static final String _DOCUMENTATION_CHECKS_DIR_NAME = "check/";
private static final String _DOCUMENTATION_DIR_LOCATION =
"src/main/resources/documentation/";
private static final String _SOURCE_CHECKS_SOURCE_LOCATION =
"src/main/java/com/liferay/source/formatter/check/";
private static final Log _log = LogFactoryUtil.getLog(
MarkdownSourceFormatterReadmeCheck.class);
private final Map> _sourceProcessorFileExtensionsMap =
new HashMap<>();
private class CheckInfo implements Comparable {
public CheckInfo(
String name, String category, String description,
String documentationLocation, CheckType checkType,
String sourceProcessorName) {
_name = name;
_category = category;
_description = description;
_documentationLocation = documentationLocation;
_checkType = checkType;
_sourceProcessorNames.add(sourceProcessorName);
}
public void addSourceProcessorName(String sourceProcessorName) {
_sourceProcessorNames.add(sourceProcessorName);
}
@Override
public int compareTo(CheckInfo checkInfo) {
return _name.compareTo(checkInfo.getName());
}
public String getCategory() {
return _category;
}
public CheckType getCheckType() {
return _checkType;
}
public String getDescription() {
return _description;
}
public String getDocumentationLocation() {
return _documentationLocation;
}
public String getName() {
return _name;
}
public List getSourceProcessorNames() {
return _sourceProcessorNames;
}
private final String _category;
private final CheckType _checkType;
private final String _description;
private final String _documentationLocation;
private final String _name;
private final List _sourceProcessorNames = new ArrayList<>();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy