ThemisMavenVersionParser.java
/*
* Themis: Java Project Framework
* Copyright 2026. Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.github.tonywasher.joceanus.themis.parser.maven;
import io.github.tonywasher.joceanus.themis.parser.base.ThemisChar;
import java.util.ArrayList;
import java.util.List;
/**
* Maven version parser.
*/
public class ThemisMavenVersionParser {
/**
* The components.
*/
private final List<Object> theComponents;
/**
* The version.
*/
private String theVersion;
/**
* The version length.
*/
private int theVersLen;
/**
* The current version index.
*/
private int theIndex;
/**
* Constructor.
*/
public ThemisMavenVersionParser() {
theComponents = new ArrayList<>();
}
/**
* Parse the version.
*
* @param pVersion the version
* @return the parsed version
*/
public ThemisMavenVersion parseVersion(final String pVersion) {
/* Initialise state */
theComponents.clear();
theVersion = pVersion;
theVersLen = pVersion.length();
theIndex = 0;
/* While we have more data */
while (theIndex < theVersLen) {
/* Parse the components */
final char myChar = theVersion.charAt(theIndex);
if (Character.isDigit(myChar)) {
theComponents.add(parseLong());
} else if (isSeparator(myChar)) {
theIndex++;
} else {
theComponents.add(parseString());
}
}
/* Prune the components */
pruneComponents();
/* Return the parsed version */
return new ThemisMavenVersion(theVersion, theComponents.toArray());
}
/**
* Parse a long component.
*
* @return the component
*/
private Long parseLong() {
final StringBuilder myBuffer = new StringBuilder();
while (theIndex < theVersLen) {
/* Access character and break loop if non-numeric */
final char myChar = theVersion.charAt(theIndex);
if (!Character.isDigit(myChar)) {
break;
}
myBuffer.append(myChar);
theIndex++;
}
return Long.parseLong(myBuffer.toString());
}
/**
* Parse a string component.
*
* @return the component
*/
private String parseString() {
final StringBuilder myBuffer = new StringBuilder();
while (theIndex < theVersLen) {
/* Access character and break loop if numeric or separator */
final char myChar = theVersion.charAt(theIndex);
if (Character.isDigit(myChar)
|| isSeparator(myChar)) {
break;
}
myBuffer.append(myChar);
theIndex++;
}
return normalise(myBuffer.toString());
}
/**
* Is the character a separator.
*
* @param pChar the character
* @return true/false
*/
private boolean isSeparator(final char pChar) {
return switch (pChar) {
case ThemisChar.PERIOD, ThemisChar.HYPHEN -> true;
default -> false;
};
}
/**
* Normalise the string component.
*
* @param pValue the component
* @return the normalised component
*/
private String normalise(final String pValue) {
return switch (pValue.toLowerCase()) {
case "alpha" -> ThemisMavenConstants.ALPHA;
case "beta" -> ThemisMavenConstants.BETA;
case "milestone" -> ThemisMavenConstants.MILESTONE;
case "final" -> ThemisMavenConstants.GA;
case "cr" -> ThemisMavenConstants.RC;
default -> pValue;
};
}
/**
* Prune components.
*/
private void pruneComponents() {
/* If we have components */
if (!theComponents.isEmpty()) {
/* Access last component */
final Object myLast = theComponents.getLast();
/* If the component is empty */
if (myLast.equals(ThemisMavenConstants.ZERO)
|| ThemisMavenConstants.GA.equalsIgnoreCase(myLast.toString())) {
/* Remove and reprune */
theComponents.removeLast();
pruneComponents();
}
}
}
}