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

com.liferay.source.formatter.check.WhitespaceCheck 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.CharPool;
import com.liferay.petra.string.StringBundler;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.tools.ToolsUtil;

import java.io.IOException;

import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Hugo Huijser
 */
public class WhitespaceCheck extends BaseFileCheck {

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

		content = _trimContent(fileName, absolutePath, content);

		content = StringUtil.replace(content, "\n\n\n", "\n\n");

		if (content.startsWith(StringPool.NEW_LINE)) {
			content = content.substring(1);
		}

		if (content.endsWith(StringPool.RETURN)) {
			content = content.substring(0, content.length() - 1);
		}

		return content;
	}

	protected String formatClosingTag(String content) {
		Matcher matcher = _closingTagPattern.matcher(content);

		return matcher.replaceAll("$1 $2");
	}

	protected String formatDoubleSpace(String line) {
		String trimmedLine = StringUtil.trim(line);

		int x = -1;

		while (true) {
			x = trimmedLine.indexOf(StringPool.DOUBLE_SPACE, x + 1);

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

			if (!ToolsUtil.isInsideQuotes(trimmedLine, x)) {
				return StringUtil.replace(
					line, trimmedLine,
					StringUtil.replaceFirst(
						trimmedLine, StringPool.DOUBLE_SPACE, StringPool.SPACE,
						x));
			}
		}
	}

	protected String formatIncorrectSyntax(String line, String regex) {
		Pattern pattern = Pattern.compile(regex);

		Matcher matcher = pattern.matcher(line);

		while (matcher.find()) {
			int x = matcher.start(1);

			if (!ToolsUtil.isInsideQuotes(line, x)) {
				return StringUtil.insert(line, StringPool.SPACE, x);
			}
		}

		return line;
	}

	protected String formatIncorrectSyntax(
		String line, String incorrectSyntax, String correctSyntax,
		boolean lineStart) {

		if (lineStart) {
			if (line.startsWith(incorrectSyntax)) {
				line = StringUtil.replaceFirst(
					line, incorrectSyntax, correctSyntax);
			}

			return line;
		}

		for (int x = -1;;) {
			x = line.indexOf(incorrectSyntax, x + 1);

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

			if (!ToolsUtil.isInsideQuotes(line, x)) {
				line = StringUtil.replaceFirst(
					line, incorrectSyntax, correctSyntax, x);
			}
		}
	}

	protected String formatSelfClosingTags(String line) {
		Matcher matcher = _selfClosingTagsPattern.matcher(line);

		while (matcher.find()) {
			int level = 1;

			for (int x = matcher.end(); x < line.length(); x++) {
				if (ToolsUtil.isInsideQuotes(line, x)) {
					continue;
				}

				char c = line.charAt(x);

				if (c == CharPool.LESS_THAN) {
					level++;
				}
				else if (c == CharPool.GREATER_THAN) {
					level--;
				}

				if (level != 0) {
					continue;
				}

				if (Objects.equals(line.substring(x - 2, x), " /")) {
					break;
				}

				char previousChar = line.charAt(x - 1);

				if (previousChar == CharPool.SPACE) {
					return StringUtil.insert(line, StringPool.SLASH, x);
				}

				if (previousChar == CharPool.SLASH) {
					return StringUtil.insert(line, StringPool.SPACE, x - 1);
				}

				return StringUtil.insert(line, " /", x);
			}
		}

		return line;
	}

	protected String formatWhitespace(
		String line, String linePart, boolean javaSource) {

		String originalLinePart = linePart;

		linePart = formatIncorrectSyntax(linePart, "catch(", "catch (", true);
		linePart = formatIncorrectSyntax(linePart, "else{", "else {", true);
		linePart = formatIncorrectSyntax(
			linePart, "else if(", "else if (", true);
		linePart = formatIncorrectSyntax(linePart, "for(", "for (", true);
		linePart = formatIncorrectSyntax(linePart, "if(", "if (", true);
		linePart = formatIncorrectSyntax(linePart, "task(", "task (", true);
		linePart = formatIncorrectSyntax(linePart, "while(", "while (", true);
		linePart = formatIncorrectSyntax(linePart, "List <", "List<", false);
		linePart = formatIncorrectSyntax(linePart, "}else", "}\nelse", true);
		linePart = formatIncorrectSyntax(linePart, "} else", "}\nelse", true);

		if (javaSource) {
			linePart = formatIncorrectSyntax(linePart, " ...", "...", false);
			linePart = formatIncorrectSyntax(linePart, " .", ".", false);
			linePart = formatIncorrectSyntax(linePart, ". ", ".", false);
			linePart = formatIncorrectSyntax(linePart, " [", "[", false);
			linePart = formatIncorrectSyntax(linePart, "{ ", "{", false);
			linePart = formatIncorrectSyntax(linePart, " }", "}", false);
			linePart = formatIncorrectSyntax(linePart, " )", ")", false);
			linePart = formatIncorrectSyntax(linePart, "( ", "(", false);
			linePart = formatIncorrectSyntax(linePart, "){", ") {", false);
			linePart = formatIncorrectSyntax(linePart, "]{", "] {", false);
			linePart = formatIncorrectSyntax(linePart, "[^\"'\\s](\\|\\|)");
			linePart = formatIncorrectSyntax(linePart, "\\|\\|([^\"'\\s])");
			linePart = formatIncorrectSyntax(linePart, "[^\"'\\s](\\&\\&)");
			linePart = formatIncorrectSyntax(linePart, "\\&\\&([^\"'\\s])");
			linePart = formatIncorrectSyntax(linePart, "\\.\\.\\.(\\w)");
			linePart = formatIncorrectSyntax(linePart, "\\w(=)");
			linePart = formatIncorrectSyntax(linePart, "=(\\w)");
			linePart = formatIncorrectSyntax(
				linePart, "for \\([^:]*[^:\"'\\s](:)");
			linePart = formatIncorrectSyntax(
				linePart, "for \\([^:]*:([^:\"'\\s])");
		}

		if (!javaSource) {
			line = StringUtil.replace(line, originalLinePart, linePart);

			return formatIncorrectSyntax(
				line, StringPool.SPACE + StringPool.TAB, StringPool.TAB, false);
		}

		if (!line.contains(StringPool.DOUBLE_SLASH)) {
			while (linePart.contains(StringPool.TAB)) {
				linePart = StringUtil.replaceLast(
					linePart, CharPool.TAB, CharPool.SPACE);
			}
		}

		if (line.contains(StringPool.DOUBLE_SLASH)) {
			line = StringUtil.replace(line, originalLinePart, linePart);

			return formatIncorrectSyntax(
				line, StringPool.SPACE + StringPool.TAB, StringPool.TAB, false);
		}

		int pos = linePart.indexOf(") ");

		if ((pos != -1) && ((pos + 2) < linePart.length()) &&
			!linePart.contains(StringPool.AT) &&
			!ToolsUtil.isInsideQuotes(linePart, pos)) {

			String linePart2 = linePart.substring(pos + 2);

			if (Character.isLetter(linePart2.charAt(0)) &&
				!linePart2.startsWith("default") &&
				!linePart2.startsWith("instanceof") &&
				!linePart2.startsWith("return") &&
				!linePart2.startsWith("throws")) {

				linePart = StringUtil.replaceFirst(
					linePart, StringPool.SPACE, StringPool.BLANK, pos);
			}
		}

		pos = linePart.indexOf(" (");

		if ((pos != -1) && !linePart.contains(StringPool.EQUAL) &&
			!ToolsUtil.isInsideQuotes(linePart, pos) &&
			(linePart.startsWith("private ") ||
			 linePart.startsWith("protected ") ||
			 linePart.startsWith("public "))) {

			linePart = StringUtil.replaceFirst(linePart, " (", "(", pos);
		}

		for (int x = -1;;) {
			int posComma = linePart.indexOf(CharPool.COMMA, x + 1);
			int posSemicolon = linePart.indexOf(CharPool.SEMICOLON, x + 1);

			if ((posComma == -1) && (posSemicolon == -1)) {
				break;
			}

			x = Math.min(posComma, posSemicolon);

			if (x == -1) {
				x = Math.max(posComma, posSemicolon);
			}

			if (ToolsUtil.isInsideQuotes(linePart, x)) {
				continue;
			}

			if (linePart.length() > (x + 1)) {
				char nextChar = linePart.charAt(x + 1);

				if ((nextChar != CharPool.APOSTROPHE) &&
					(nextChar != CharPool.CLOSE_PARENTHESIS) &&
					(nextChar != CharPool.SPACE) &&
					(nextChar != CharPool.STAR)) {

					linePart = StringUtil.insert(
						linePart, StringPool.SPACE, x + 1);
				}
			}

			if (x > 0) {
				char previousChar = linePart.charAt(x - 1);

				if (previousChar == CharPool.SPACE) {
					linePart =
						linePart.substring(0, x - 1) + linePart.substring(x);
				}
			}
		}

		line = StringUtil.replace(line, originalLinePart, linePart);

		return formatIncorrectSyntax(
			line, StringPool.SPACE + StringPool.TAB, StringPool.TAB, false);
	}

	protected boolean isAllowLeadingSpaces(
		String fileName, String absolutePath) {

		return isAttributeValue(_ALLOW_LEADING_SPACES_KEY, absolutePath);
	}

	protected boolean isAllowTrailingEmptyLines(
		String fileName, String absolutePath) {

		return isAttributeValue(_ALLOW_TRAILING_EMPTY_LINES, absolutePath);
	}

	protected boolean isAllowTrailingSpaces(String line) {
		return false;
	}

	protected String trimLine(
		String fileName, String absolutePath, String line) {

		String trimmedTrailingLine = StringUtil.trimTrailing(line);

		if (trimmedTrailingLine.length() == 0) {
			return StringPool.BLANK;
		}

		if (!isAllowTrailingSpaces(line) &&
			(!isAttributeValue(
				_ALLOW_TRAILING_DOUBLE_SPACE_KEY, absolutePath) ||
			 !line.endsWith(StringPool.DOUBLE_SPACE))) {

			line = trimmedTrailingLine;
		}

		if (!isAttributeValue(_ALLOW_DOUBLE_SPACE_KEY, absolutePath)) {
			line = formatDoubleSpace(line);
		}

		if (isAllowLeadingSpaces(fileName, absolutePath) ||
			line.startsWith(" *")) {

			return line;
		}

		while (line.matches("^\t*    .*")) {
			line = StringUtil.replaceFirst(
				line, StringPool.FOUR_SPACES, StringPool.TAB);
		}

		while (line.startsWith(StringPool.SPACE)) {
			line = StringUtil.replaceFirst(
				line, CharPool.SPACE, StringPool.BLANK);
		}

		return line;
	}

	protected String trimLine(
		String fileName, String absolutePath, String content, String line,
		int lineNumber) {

		return trimLine(fileName, absolutePath, line);
	}

	private String _trimContent(
			String fileName, String absolutePath, String content)
		throws IOException {

		StringBundler sb = new StringBundler();

		try (UnsyncBufferedReader unsyncBufferedReader =
				new UnsyncBufferedReader(new UnsyncStringReader(content))) {

			String line = null;
			int lineNumber = 0;

			while ((line = unsyncBufferedReader.readLine()) != null) {
				lineNumber++;

				sb.append(
					trimLine(
						fileName, absolutePath, content, line, lineNumber));
				sb.append("\n");
			}
		}

		if (isAllowTrailingEmptyLines(fileName, absolutePath) &&
			content.endsWith("\n")) {

			return sb.toString();
		}

		content = sb.toString();

		if (content.endsWith("\n")) {
			content = content.substring(0, content.length() - 1);
		}

		return content;
	}

	private static final String _ALLOW_DOUBLE_SPACE_KEY = "allowDoubleSpace";

	private static final String _ALLOW_LEADING_SPACES_KEY =
		"allowLeadingSpaces";

	private static final String _ALLOW_TRAILING_DOUBLE_SPACE_KEY =
		"allowTrailingDoubleSpace";

	private static final String _ALLOW_TRAILING_EMPTY_LINES =
		"allowTrailingEmptyLines";

	private static final Pattern _closingTagPattern = Pattern.compile(
		"(<[\\w-.:]+)(/>)");
	private static final Pattern _selfClosingTagsPattern = Pattern.compile(
		"<(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|" +
			"param|source|track|wbr)(?!( />|\\w))");

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy