com.liferay.source.formatter.check.YMLDefinitionOrderCheck 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.StringBundler;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.util.HashMapBuilder;
import com.liferay.portal.kernel.util.NaturalOrderStringComparator;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.source.formatter.check.util.YMLSourceUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Hugo Huijser
* @author Alan Huang
*/
public class YMLDefinitionOrderCheck extends BaseFileCheck {
@Override
protected String doProcess(
String fileName, String absolutePath, String content) {
if (fileName.endsWith(".travis.yml")) {
return content;
}
List directives = YMLSourceUtil.splitDirectives(content);
StringBundler sb = new StringBundler(directives.size() * 2);
for (String directive : directives) {
sb.append(_sortDefinitions(fileName, directive, StringPool.BLANK));
sb.append("\n---\n");
}
sb.setIndex(sb.index() - 1);
content = _sortFeatureFlags(sb.toString());
if (fileName.endsWith("docker-compose.yaml")) {
content = _sortPorts(sb.toString());
}
return _sortPathParameters(content);
}
private List _combineComments(
List definitions, String indent) {
List definitionsList = new ArrayList<>();
StringBundler sb = new StringBundler();
String previousDefinition = StringPool.BLANK;
for (String definition : definitions) {
if (definition.startsWith(indent + StringPool.POUND)) {
sb.append(definition);
sb.append("\n");
}
else if (previousDefinition.startsWith(indent + StringPool.POUND)) {
sb.append(definition);
definitionsList.add(sb.toString());
sb.setIndex(0);
}
else {
definitionsList.add(definition);
}
previousDefinition = definition;
}
if (sb.index() > 0) {
definitionsList.add(StringUtil.trimTrailing(sb.toString()));
}
return definitionsList;
}
private String _getParameterType(String definition) {
return definition.replaceAll("(?s).*in: (\\S*).*", "$1");
}
private int _getParameterTypeWeight(String definitionKey) {
if (_parameterTypesWeightMap.containsKey(definitionKey)) {
return _parameterTypesWeightMap.get(definitionKey);
}
return -1;
}
private String _removeComments(String definition) {
int y = definition.indexOf("\n");
if (y == -1) {
return definition;
}
int x = 0;
String line = definition.substring(x, y);
while (line.matches(" *#.*")) {
x = y + 1;
y = definition.indexOf("\n", x);
if (y == -1) {
return definition;
}
line = definition.substring(x, y);
}
return definition.substring(x);
}
private List _removeDuplicateAttribute(List list) {
List definitions = new ArrayList<>();
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if (!definitions.contains(s) || s.startsWith("{{") ||
s.startsWith("#")) {
definitions.add(s);
}
}
return definitions;
}
private String _sortDefinitions(
String fileName, String content, String indent) {
List definitions = YMLSourceUtil.getDefinitions(
content, indent);
if ((definitions.size() == 1) && !content.contains("\n")) {
return content;
}
definitions = _removeDuplicateAttribute(definitions);
definitions = _combineComments(definitions, indent);
List oldDefinitions = new ArrayList<>(definitions);
Collections.sort(
definitions,
new Comparator() {
@Override
public int compare(String definition1, String definition2) {
String trimmedDefinition1 = StringUtil.trimLeading(
definition1);
String trimmedDefinition2 = StringUtil.trimLeading(
definition2);
if (trimmedDefinition1.startsWith("{{") ||
trimmedDefinition2.startsWith("{{") ||
Validator.isNull(trimmedDefinition1) ||
Validator.isNull(trimmedDefinition2)) {
return 0;
}
String[] definition1Lines = StringUtil.splitLines(
_removeComments(definition1));
String[] definition2Lines = StringUtil.splitLines(
_removeComments(definition2));
String trimmedDefinition1Line = definition1Lines[0];
String trimmedDefinition2Line = definition2Lines[0];
if (trimmedDefinition1Line.equals(StringPool.DASH) ||
trimmedDefinition2Line.equals(StringPool.DASH)) {
if (definition1Lines[1].contains("in: ") &&
definition2Lines[1].contains("in: ")) {
return _sortSpecificDefinitions(
definition1, definition2, "name");
}
return 0;
}
if (trimmedDefinition1Line.startsWith("in:") ||
trimmedDefinition2Line.startsWith("in:")) {
if (trimmedDefinition1Line.startsWith("in:")) {
return -1;
}
return 1;
}
String definition1Key = definition1.replaceAll(
"( *#.*(\\Z|\n))*(.*)", "$3");
String definition2Key = definition2.replaceAll(
"( *#.*(\\Z|\n))*(.*)", "$3");
if (Validator.isNull(definition1Key) ||
Validator.isNull(definition2Key)) {
return 0;
}
definition1Key = definition1Key.replaceAll("(?s):\n.*", "");
definition2Key = definition2Key.replaceAll("(?s):\n.*", "");
return definition1Key.compareTo(definition2Key);
}
});
if (!oldDefinitions.equals(definitions)) {
StringBundler sb = new StringBundler();
for (String definition : definitions) {
sb.append(definition);
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();
}
}
definitions = YMLSourceUtil.getDefinitions(content, indent);
for (String definition : definitions) {
String[] lines = StringUtil.splitLines(definition);
if ((lines.length != 0) &&
lines[0].matches(" *(description:|.+: +.+)")) {
continue;
}
String nestedDefinitionIndent =
YMLSourceUtil.getNestedDefinitionIndent(definition);
if (!nestedDefinitionIndent.equals(StringPool.BLANK)) {
content = StringUtil.replaceFirst(
content, definition,
_sortDefinitions(
fileName, definition, nestedDefinitionIndent));
}
}
return content;
}
private String _sortFeatureFlags(String content) {
int x = -1;
while (true) {
x = content.indexOf("featureFlags: ", x + 1);
if (x == -1) {
return content;
}
String featureFlags = content.substring(x + 14);
int y = featureFlags.indexOf("\n");
if (y != -1) {
featureFlags = featureFlags.substring(0, y);
}
String[] array = featureFlags.split(",");
if (array.length < 2) {
return content;
}
Arrays.sort(array, new NaturalOrderStringComparator());
String newFeatureFlags = StringUtil.merge(array);
if (!featureFlags.equals(newFeatureFlags)) {
return StringUtil.replaceFirst(
content, featureFlags, newFeatureFlags, x);
}
}
}
private String _sortPathParameters(String content) {
Matcher matcher1 = _pathPattern1.matcher(content);
while (matcher1.find()) {
String path = matcher1.group();
String[] lines = path.split("\n", 2);
Matcher matcher2 = _pathPattern2.matcher(lines[0]);
Map inPathsMap = new LinkedHashMap<>();
while (matcher2.find()) {
inPathsMap.put(matcher2.group(1), "");
}
int inPathCount = inPathsMap.size();
Pattern pattern = Pattern.compile(
"( *-\n( +)in: path(\n\\2.+)*\n){" + inPathCount + "}");
matcher2 = pattern.matcher(lines[1]);
while (matcher2.find()) {
String inPaths = matcher2.group();
Matcher matcher3 = _pathPattern3.matcher(inPaths);
while (matcher3.find()) {
String inPath = matcher3.group();
inPathsMap.replace(
inPath.replaceAll("(?s).*name: (\\S+).*", "$1"),
inPath);
}
StringBundler sb = new StringBundler(inPathCount);
for (Map.Entry entry : inPathsMap.entrySet()) {
sb.append(entry.getValue());
}
content = StringUtil.replaceFirst(
content, inPaths, sb.toString());
}
}
return content;
}
private String _sortPorts(String content) {
Matcher matcher = _portsPattern.matcher(content);
while (matcher.find()) {
String indent = matcher.group(1) + StringPool.FOUR_SPACES;
String ports = matcher.group(2);
String trimmedPorts = StringUtil.trimLeading(ports);
trimmedPorts = trimmedPorts.replaceAll(" *-\n +", "");
String[] portsArray = StringUtil.splitLines(trimmedPorts);
Arrays.sort(portsArray);
StringBundler sb = new StringBundler(portsArray.length * 8);
for (String port : portsArray) {
sb.append(StringPool.NEW_LINE);
sb.append(indent);
sb.append(StringPool.DASH);
sb.append(StringPool.NEW_LINE);
sb.append(indent);
sb.append(StringPool.SPACE);
sb.append(StringPool.SPACE);
sb.append(port);
}
String newPorts = sb.toString();
if (!ports.equals(newPorts)) {
return StringUtil.replaceFirst(
content, ports, newPorts, matcher.start(2));
}
}
return content;
}
private int _sortSpecificDefinitions(
String definition1, String definition2, String key) {
String parameter1Type = _getParameterType(definition1);
String parameter2Type = _getParameterType(definition2);
Pattern pattern = Pattern.compile(
"^ *" + key + ": *(\\S*)(\n|\\Z)", Pattern.MULTILINE);
String value1 = StringPool.BLANK;
Matcher matcher = pattern.matcher(definition1);
if (matcher.find()) {
value1 = matcher.group(1);
}
String value2 = StringPool.BLANK;
matcher = pattern.matcher(definition2);
if (matcher.find()) {
value2 = matcher.group(1);
}
if (parameter1Type.equals(parameter2Type)) {
return value1.compareTo(value2);
}
return _getParameterTypeWeight(parameter1Type) -
_getParameterTypeWeight(parameter2Type);
}
private static final Map _parameterTypesWeightMap =
HashMapBuilder.put(
"cookie", 4
).put(
"header", 3
).put(
"path", 1
).put(
"query", 2
).build();
private static final Pattern _pathPattern1 = Pattern.compile(
"(?<=\n)( *)\"([^{}\"]*\\{[^}]+\\}[^{}\"]*){2,}\":(\n\\1 .*)*");
private static final Pattern _pathPattern2 = Pattern.compile(
"\\{([^{}]+)\\}");
private static final Pattern _pathPattern3 = Pattern.compile(
" *-\n( +)in: path(\n\\1.+)*\n");
private static final Pattern _portsPattern = Pattern.compile(
"\n( +)ports:((\n +-\\s+\\d{4}:\\d{4}){2,})");
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy