Skip to content

Commit 903e570

Browse files
committed
refactor(downloader): use semver4j for version comparison
Replace the hand-rolled version/pre-release comparison with the org.semver4j:semver4j library, which implements semver ordering (numeric pre-release identifiers, release > pre-release) correctly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VEHLaBE3PCoXkWraXA32Zp
1 parent 6d09e85 commit 903e570

2 files changed

Lines changed: 10 additions & 75 deletions

File tree

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ dependencies {
5151
implementation("org.slf4j:slf4j-api:2.0.17")
5252
implementation("org.kohsuke:github-api:1.327")
5353
implementation("org.apache.commons:commons-compress:1.28.0")
54+
implementation("org.semver4j:semver4j:5.8.0")
5455

5556
testImplementation("org.assertj:assertj-core:3.27.7")
5657

src/main/java/com/github/_1c_syntax/utils/downloader/BslLanguageServerDownloader.java

Lines changed: 9 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.kohsuke.github.GitHub;
3131
import org.kohsuke.github.GitHubBuilder;
3232
import org.kohsuke.github.extras.HttpClientGitHubConnector;
33+
import org.semver4j.Semver;
3334

3435
import java.io.IOException;
3536
import java.io.InputStream;
@@ -402,84 +403,17 @@ private static String normalizeVersion(String tag) {
402403
}
403404

404405
/**
405-
* Сравнивает две версии в формате {@code major.minor.patch[-preRelease]}.
406-
* Релиз считается новее одноимённого pre-release ({@code 1.0.0 > 1.0.0-rc1}).
406+
* Сравнивает две версии по правилам semver: релиз новее одноимённого pre-release, числовые
407+
* идентификаторы pre-release сравниваются как числа ({@code 1.0.0-rc.10 > 1.0.0-rc.9}).
408+
* Если хотя бы одна строка не парсится как semver — используется лексикографическое сравнение.
407409
*/
408410
static int compareVersions(String left, String right) {
409-
var leftParts = left.split("-", 2);
410-
var rightParts = right.split("-", 2);
411-
412-
var coreCompare = compareCore(leftParts[0], rightParts[0]);
413-
if (coreCompare != 0) {
414-
return coreCompare;
415-
}
416-
417-
var leftPre = leftParts.length > 1 ? leftParts[1] : "";
418-
var rightPre = rightParts.length > 1 ? rightParts[1] : "";
419-
if (leftPre.isEmpty() && rightPre.isEmpty()) {
420-
return 0;
421-
}
422-
if (leftPre.isEmpty()) {
423-
return 1;
424-
}
425-
if (rightPre.isEmpty()) {
426-
return -1;
427-
}
428-
return comparePreRelease(leftPre, rightPre);
429-
}
430-
431-
/**
432-
* Сравнивает pre-release суффиксы по точкам-разделённым идентификаторам: числовые идентификаторы
433-
* сравниваются как числа ({@code rc.10 > rc.9}), нечисловые — лексикографически.
434-
*/
435-
private static int comparePreRelease(String left, String right) {
436-
var leftIds = left.split("\\.");
437-
var rightIds = right.split("\\.");
438-
var length = Math.max(leftIds.length, rightIds.length);
439-
for (var i = 0; i < length; i++) {
440-
if (i >= leftIds.length) {
441-
return -1;
442-
}
443-
if (i >= rightIds.length) {
444-
return 1;
445-
}
446-
var leftId = leftIds[i];
447-
var rightId = rightIds[i];
448-
var bothNumeric = isNumeric(leftId) && isNumeric(rightId);
449-
var comparison = bothNumeric
450-
? Integer.compare(parseInt(leftId), parseInt(rightId))
451-
: leftId.compareTo(rightId);
452-
if (comparison != 0) {
453-
return comparison;
454-
}
455-
}
456-
return 0;
457-
}
458-
459-
private static boolean isNumeric(String value) {
460-
return !value.isEmpty() && value.chars().allMatch(Character::isDigit);
461-
}
462-
463-
private static int compareCore(String left, String right) {
464-
var leftNumbers = left.split("\\.");
465-
var rightNumbers = right.split("\\.");
466-
var length = Math.max(leftNumbers.length, rightNumbers.length);
467-
for (var i = 0; i < length; i++) {
468-
var leftValue = i < leftNumbers.length ? parseInt(leftNumbers[i]) : 0;
469-
var rightValue = i < rightNumbers.length ? parseInt(rightNumbers[i]) : 0;
470-
if (leftValue != rightValue) {
471-
return Integer.compare(leftValue, rightValue);
472-
}
473-
}
474-
return 0;
475-
}
476-
477-
private static int parseInt(String value) {
478-
try {
479-
return Integer.parseInt(value.strip());
480-
} catch (NumberFormatException e) {
481-
return 0;
411+
var leftVersion = Semver.parse(normalizeVersion(left));
412+
var rightVersion = Semver.parse(normalizeVersion(right));
413+
if (leftVersion == null || rightVersion == null) {
414+
return normalizeVersion(left).compareTo(normalizeVersion(right));
482415
}
416+
return leftVersion.compareTo(rightVersion);
483417
}
484418

485419
private static Os currentOs() {

0 commit comments

Comments
 (0)