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

com.liferay.source.formatter.check.PythonClassesAndMethodsOrderCheck Maven / Gradle / Ivy

There is a newer version: 1.0.1457
Show 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.StringBundler;
import com.liferay.petra.string.StringPool;
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.PythonSourceUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Alan Huang
 */
public class PythonClassesAndMethodsOrderCheck extends BaseFileCheck {

	@Override
	protected String doProcess(
		String fileName, String absolutePath, String content) {

		content = _formatClassDefinationHeader(absolutePath, content);

		return _sortItems(fileName, content, StringPool.BLANK);
	}

	private List _combineAnnotationsAndComments(
		List statements, String indent) {

		List statementsList = new ArrayList<>();

		StringBundler sb = new StringBundler();

		String previousStatement = StringPool.BLANK;

		for (String statement : statements) {
			if (statement.startsWith(indent + StringPool.AT) ||
				statement.startsWith(indent + StringPool.POUND)) {

				sb.append(statement);
				sb.append("\n");
			}
			else if (previousStatement.startsWith(indent + StringPool.AT) ||
					 previousStatement.startsWith(indent + StringPool.POUND)) {

				sb.append(statement);

				statementsList.add(sb.toString());

				sb.setIndex(0);
			}
			else {
				statementsList.add(statement);
			}

			previousStatement = statement;
		}

		if (sb.index() > 0) {
			statementsList.add(StringUtil.trimTrailing(sb.toString()));
		}

		return statementsList;
	}

	private String _formatClassDefinationHeader(
		String absolutePath, String content) {

		int maxLineLength = 0;

		try {
			maxLineLength = Integer.parseInt(
				getAttributeValue(_MAX_LINE_LENGTH, absolutePath));
		}
		catch (NumberFormatException numberFormatException) {
			return content;
		}

		Matcher matcher = _classDefinationHeaderPattern1.matcher(content);

		while (matcher.find()) {
			String indent = matcher.group(1);
			String className = matcher.group(2);

			List parentClassList = ListUtil.fromString(
				matcher.group(4), StringPool.COMMA);

			for (int i = 0; i < parentClassList.size(); i++) {
				parentClassList.set(i, StringUtil.trim(parentClassList.get(i)));
			}

			StringBundler sb = new StringBundler(7);

			sb.append(indent);
			sb.append("class ");
			sb.append(className);

			if (ListUtil.isNotEmpty(parentClassList)) {
				sb.append(StringPool.OPEN_PARENTHESIS);
				sb.append(
					ListUtil.toString(
						parentClassList, StringPool.BLANK,
						StringPool.COMMA_AND_SPACE));
				sb.append(StringPool.CLOSE_PARENTHESIS);
			}

			sb.append(StringPool.COLON);

			content = StringUtil.replace(
				content, matcher.group(),
				_splitLine(sb.toString(), indent + "\t", maxLineLength) +
					"\n\n");
		}

		return content;
	}

	private int _sortClasses(String class1, String class2) {
		Matcher matcher = _classDefinationHeaderPattern2.matcher(class1);

		if (!matcher.find()) {
			return 0;
		}

		String className1 = matcher.group(1);

		List parentClassList = ListUtil.fromString(
			matcher.group(3), StringPool.COMMA);

		for (int i = 0; i < parentClassList.size(); i++) {
			parentClassList.set(i, StringUtil.trim(parentClassList.get(i)));
		}

		matcher = _classDefinationHeaderPattern2.matcher(class2);

		if (!matcher.find()) {
			return 0;
		}

		String className2 = matcher.group(1);

		if (className1.compareTo(className2) < 0) {
			if (!parentClassList.contains(className2)) {
				return -1;
			}

			return 1;
		}

		return className1.compareTo(className2);
	}

	private int _sortItems(String statement1, String statement2) {
		String trimmedStatement1 = StringUtil.trimLeading(
			statement1.replaceAll("(\t*[#@].*(\\Z|\n))*(.*)", "$3"));
		String trimmedStatement2 = StringUtil.trimLeading(
			statement2.replaceAll("(\t*[#@].*(\\Z|\n))*(.*)", "$3"));

		if (Validator.isNull(trimmedStatement1) ||
			Validator.isNull(trimmedStatement2)) {

			return 0;
		}

		if (trimmedStatement1.startsWith("class ") &&
			trimmedStatement2.startsWith("class ")) {

			return _sortClasses(trimmedStatement1, trimmedStatement2);
		}

		if (trimmedStatement1.startsWith("def ") &&
			trimmedStatement2.startsWith("def ")) {

			return _sortMethods(trimmedStatement1, trimmedStatement2);
		}

		return 0;
	}

	private String _sortItems(String fileName, String content, String indent) {
		List statements = PythonSourceUtil.getPythonStatements(
			content, indent);

		statements = _combineAnnotationsAndComments(statements, indent);

		List oldStatements = new ArrayList<>(statements);

		Collections.sort(
			statements,
			new Comparator() {

				@Override
				public int compare(String statement1, String statement2) {
					return _sortItems(statement1, statement2);
				}

			});

		if (!oldStatements.equals(statements)) {
			StringBundler sb = new StringBundler(statements.size() * 2);

			for (String statement : statements) {
				sb.append(statement);
				sb.append("\n");
			}

			sb.setIndex(sb.index() - 1);

			String[] lines = content.split("\n");

			if (!indent.equals("")) {
				content = lines[0] + "\n" + sb.toString();
			}
			else {
				content = sb.toString();
			}
		}

		statements = PythonSourceUtil.getPythonStatements(content, indent);

		for (String statement : statements) {
			String nestedStatementIndent =
				PythonSourceUtil.getNestedStatementIndent(statement);

			if (!nestedStatementIndent.equals(StringPool.BLANK)) {
				content = StringUtil.replaceFirst(
					content, statement,
					_sortItems(fileName, statement, nestedStatementIndent));
			}
		}

		return content;
	}

	private int _sortMethods(String method1, String method2) {
		String[] lines1 = method1.split("\n", 2);

		String methodName1 = lines1[0].replaceFirst("def (\\w+).*", "$1");

		String[] lines2 = method2.split("\n", 2);

		String methodName2 = lines2[0].replaceFirst("def (\\w+).*", "$1");

		return methodName1.compareTo(methodName2);
	}

	private String _splitLine(String line, String indent, int maxLineLength) {
		if (line.length() <= maxLineLength) {
			return line;
		}

		int pos = line.indexOf(StringPool.COMMA_AND_SPACE, indent.length());

		if (pos == -1) {
			return line;
		}

		if (pos > maxLineLength) {
			return StringBundler.concat(
				line.substring(0, pos + 1), StringPool.NEW_LINE,
				_splitLine(
					indent + StringUtil.trimLeading(line.substring(pos + 2)),
					indent, maxLineLength));
		}

		pos = line.lastIndexOf(StringPool.COMMA_AND_SPACE, maxLineLength);

		return StringBundler.concat(
			line.substring(0, pos + 1), StringPool.NEW_LINE,
			_splitLine(
				indent + StringUtil.trimLeading(line.substring(pos + 2)),
				indent, maxLineLength));
	}

	private static final String _MAX_LINE_LENGTH = "maxLineLength";

	private static final Pattern _classDefinationHeaderPattern1 =
		Pattern.compile(
			"(?<=\n)(\t*)class (\\w+)(\\((.*?)\\))?:\n+", Pattern.DOTALL);
	private static final Pattern _classDefinationHeaderPattern2 =
		Pattern.compile("class (\\w+)(\\((.*?)\\))?:", Pattern.DOTALL);

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy