[Gradle, JS] Use not inverted visitor but straightforward visitor
^KT-41054 fixed
This commit is contained in:
+50
-4
@@ -6,16 +6,25 @@
|
|||||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||||
|
|
||||||
import com.github.gundy.semver4j.model.Version
|
import com.github.gundy.semver4j.model.Version
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmVersionInvertedVisitor.Companion.GT
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmVersionInvertedVisitor.Companion.GTEQ
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmVersionInvertedVisitor.Companion.LT
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmVersionInvertedVisitor.Companion.LTEQ
|
||||||
|
|
||||||
data class NpmRange(
|
data class NpmRange(
|
||||||
val startVersion: SemVer? = null,
|
val startVersion: SemVer? = null,
|
||||||
val startInclusive: Boolean = false,
|
val startInclusive: Boolean = false,
|
||||||
val endVersion: SemVer? = null,
|
val endVersion: SemVer? = null,
|
||||||
val endInclusive: Boolean = false
|
val endInclusive: Boolean = false
|
||||||
)
|
) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "${if (startVersion != null) "${if (startInclusive) GTEQ else GT}$startVersion" else ""} ${if (endVersion != null) "${if (endInclusive) LTEQ else LT}$endVersion" else ""}"
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val NONE_RANGE = NpmRange(
|
val NONE_RANGE = NpmRange(
|
||||||
startVersion = Version.fromString(NONE_VERSION)
|
endVersion = Version.fromString(NONE_VERSION)
|
||||||
.toSemVer()
|
.toSemVer()
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,12 +45,49 @@ infix fun NpmRange.union(other: NpmRange): List<NpmRange> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun NpmRange.invert(): List<NpmRange> {
|
||||||
|
val result = mutableListOf<NpmRange>()
|
||||||
|
if (startVersion != null || endVersion == null) {
|
||||||
|
result.add(
|
||||||
|
NpmRange(
|
||||||
|
endVersion = startVersion,
|
||||||
|
endInclusive = !startInclusive
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endVersion != null || startVersion == null) {
|
||||||
|
result.add(
|
||||||
|
NpmRange(
|
||||||
|
startVersion = endVersion,
|
||||||
|
startInclusive = !endInclusive
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.distinct()
|
||||||
|
}
|
||||||
|
|
||||||
|
infix fun List<NpmRange>.intersect(others: List<NpmRange>): List<NpmRange> = flatMap { current ->
|
||||||
|
others.mapNotNull { other ->
|
||||||
|
current intersect other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
infix fun NpmRange.intersect(other: NpmRange): NpmRange? {
|
infix fun NpmRange.intersect(other: NpmRange): NpmRange? {
|
||||||
if (!isIntersect(other)) return null
|
if (!isIntersect(other)) return null
|
||||||
|
|
||||||
val startVersion = max(this.startVersion, other.startVersion)
|
val startVersion = when {
|
||||||
|
startVersion == null -> other.startVersion
|
||||||
|
other.startVersion == null -> startVersion
|
||||||
|
else -> max(this.startVersion, other.startVersion)
|
||||||
|
}
|
||||||
|
|
||||||
val endVersion = min(this.endVersion, other.endVersion)
|
val endVersion = when {
|
||||||
|
endVersion == null -> other.endVersion
|
||||||
|
other.endVersion == null -> endVersion
|
||||||
|
else -> min(this.endVersion, other.endVersion)
|
||||||
|
}
|
||||||
|
|
||||||
return NpmRange(
|
return NpmRange(
|
||||||
startVersion = startVersion,
|
startVersion = startVersion,
|
||||||
|
|||||||
+1
-8
@@ -31,14 +31,7 @@ class NpmVersionConstraint(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val version = buildNpmVersion(listOf(requiredVersion), rejectedVersions)
|
return buildNpmVersion(listOf(requiredVersion), rejectedVersions)
|
||||||
|
|
||||||
val requiredRange = "^$version"
|
|
||||||
return if (SemVer.valid(requiredRange) && SemVer.satisfies(version, requiredRange)) {
|
|
||||||
requiredRange
|
|
||||||
} else {
|
|
||||||
version
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+95
-26
@@ -10,17 +10,17 @@ import com.github.gundy.semver4j.generated.grammar.NodeSemverExpressionParser
|
|||||||
import com.github.gundy.semver4j.model.Version
|
import com.github.gundy.semver4j.model.Version
|
||||||
import org.antlr.v4.runtime.tree.TerminalNode
|
import org.antlr.v4.runtime.tree.TerminalNode
|
||||||
|
|
||||||
class NpmVersionInvertedVisitor : NodeSemverExpressionBaseVisitor<NpmRange>() {
|
class NpmVersionInvertedVisitor : NodeSemverExpressionBaseVisitor<List<NpmRange?>>() {
|
||||||
override fun visitEmptyRange(ctx: NodeSemverExpressionParser.EmptyRangeContext): NpmRange =
|
override fun visitEmptyRange(ctx: NodeSemverExpressionParser.EmptyRangeContext): List<NpmRange?> =
|
||||||
NONE_RANGE
|
listOf(null)
|
||||||
|
|
||||||
override fun visitWildcard(ctx: NodeSemverExpressionParser.WildcardContext): NpmRange =
|
override fun visitWildcard(ctx: NodeSemverExpressionParser.WildcardContext): List<NpmRange?> =
|
||||||
NONE_RANGE
|
listOf(null)
|
||||||
|
|
||||||
override fun visitWildcardRange(ctx: NodeSemverExpressionParser.WildcardRangeContext): NpmRange =
|
override fun visitWildcardRange(ctx: NodeSemverExpressionParser.WildcardRangeContext): List<NpmRange> =
|
||||||
inverseVersion(ctx.partialWildcardSemver().text)
|
listOf(eq(ctx.partialWildcardSemver().text))
|
||||||
|
|
||||||
override fun visitOperator(ctx: NodeSemverExpressionParser.OperatorContext): NpmRange {
|
override fun visitOperator(ctx: NodeSemverExpressionParser.OperatorContext): List<NpmRange> {
|
||||||
val eq: TerminalNode? = ctx.unaryOperator().EQ()
|
val eq: TerminalNode? = ctx.unaryOperator().EQ()
|
||||||
val gt: TerminalNode? = ctx.unaryOperator().GT()
|
val gt: TerminalNode? = ctx.unaryOperator().GT()
|
||||||
val lt: TerminalNode? = ctx.unaryOperator().LT()
|
val lt: TerminalNode? = ctx.unaryOperator().LT()
|
||||||
@@ -28,51 +28,120 @@ class NpmVersionInvertedVisitor : NodeSemverExpressionBaseVisitor<NpmRange>() {
|
|||||||
val version = ctx.partialWildcardSemver().text
|
val version = ctx.partialWildcardSemver().text
|
||||||
|
|
||||||
if (gt == null && lt == null) {
|
if (gt == null && lt == null) {
|
||||||
return inverseVersion(version)
|
return listOf(eq(version))
|
||||||
}
|
}
|
||||||
|
|
||||||
val invertedEqToken = if (eq != null) EQ else ""
|
val eqToken = eq != null
|
||||||
|
|
||||||
if (lt != null) {
|
if (lt != null) {
|
||||||
return "$GT$invertedEqToken$version"
|
return listOf(
|
||||||
|
if (eqToken) lteq(version) else lt(version)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return "$LT$invertedEqToken$version"
|
return listOf(
|
||||||
|
if (eqToken) gteq(version) else gt(version)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitWildcardOperator(ctx: NodeSemverExpressionParser.WildcardOperatorContext): NpmRange =
|
override fun visitWildcardOperator(ctx: NodeSemverExpressionParser.WildcardOperatorContext): List<NpmRange?> =
|
||||||
NONE_RANGE
|
listOf(null)
|
||||||
|
|
||||||
override fun visitTildeRange(ctx: NodeSemverExpressionParser.TildeRangeContext): NpmRange {
|
override fun visitTildeRange(ctx: NodeSemverExpressionParser.TildeRangeContext): List<NpmRange> {
|
||||||
val version = Version.fromString(ctx.fullSemver().text)
|
val version = Version.fromString(ctx.fullSemver().text)
|
||||||
val nextVersion = version
|
val nextVersion = version
|
||||||
.incrementMinor()
|
.incrementMinor()
|
||||||
|
|
||||||
return "$LT$version $OR $GTEQ$nextVersion"
|
return listOf(gteq(version))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCaretRange(ctx: NodeSemverExpressionParser.CaretRangeContext): NpmRange {
|
override fun visitCaretRange(ctx: NodeSemverExpressionParser.CaretRangeContext): List<NpmRange> {
|
||||||
val version = Version.fromString(ctx.fullSemver().text)
|
val version = Version.fromString(ctx.fullSemver().text)
|
||||||
val nextVersion = version
|
val nextVersion = version
|
||||||
.incrementMajor()
|
.incrementMajor()
|
||||||
|
|
||||||
return "$LT$version $OR $GTEQ$nextVersion"
|
return lt(version) union gteq(nextVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFullySpecifiedSemver(ctx: NodeSemverExpressionParser.FullySpecifiedSemverContext): NpmRange =
|
override fun visitFullySpecifiedSemver(ctx: NodeSemverExpressionParser.FullySpecifiedSemverContext): List<NpmRange> =
|
||||||
inverseVersion(ctx.fullSemver().text)
|
inverseVersion(ctx.fullSemver().text)
|
||||||
|
|
||||||
override fun visitLogicalAndOfSimpleExpressions(ctx: NodeSemverExpressionParser.LogicalAndOfSimpleExpressionsContext): NpmRange =
|
override fun visitLogicalAndOfSimpleExpressions(ctx: NodeSemverExpressionParser.LogicalAndOfSimpleExpressionsContext): List<NpmRange?> =
|
||||||
ctx.simple()
|
try {
|
||||||
.joinToString(OR) { visit(it) }
|
ctx.simple()
|
||||||
|
.flatMap { visit(it) }
|
||||||
|
.filterNotNull()
|
||||||
|
.reduce { acc: NpmRange?, next: NpmRange ->
|
||||||
|
val npmRange = if (acc == null) null else acc intersect next
|
||||||
|
npmRange
|
||||||
|
}
|
||||||
|
} catch (e: UnsupportedOperationException) {
|
||||||
|
null
|
||||||
|
}.let { listOf(it) }
|
||||||
|
|
||||||
override fun visitLogicalOrOfMultipleRanges(ctx: NodeSemverExpressionParser.LogicalOrOfMultipleRangesContext): NpmRange =
|
override fun visitLogicalOrOfMultipleRanges(ctx: NodeSemverExpressionParser.LogicalOrOfMultipleRangesContext): List<NpmRange?> =
|
||||||
ctx.basicRange()
|
ctx.basicRange()
|
||||||
.joinToString(AND) { visitBasicRange(it) }
|
.flatMap { visitBasicRange(it) }
|
||||||
|
.onEach { if (it == null) return listOf(null) }
|
||||||
|
.filterNotNull()
|
||||||
|
.fold(listOf<NpmRange>()) { ranges, range ->
|
||||||
|
if (ranges.isEmpty()) listOf(range)
|
||||||
|
else ranges
|
||||||
|
.flatMap { it union range }
|
||||||
|
|
||||||
private fun inverseVersion(version: String): String =
|
}
|
||||||
"$GT$version $OR $LT$version"
|
|
||||||
|
|
||||||
|
private fun inverseVersion(version: String): List<NpmRange> =
|
||||||
|
inverseVersion(Version.fromString(version))
|
||||||
|
|
||||||
|
private fun inverseVersion(version: Version): List<NpmRange> =
|
||||||
|
gt(version) union lt(version)
|
||||||
|
|
||||||
|
private fun lt(version: String): NpmRange =
|
||||||
|
lt(Version.fromString(version))
|
||||||
|
|
||||||
|
private fun lt(version: Version): NpmRange =
|
||||||
|
NpmRange(
|
||||||
|
endVersion = version.toSemVer(),
|
||||||
|
endInclusive = false
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun lteq(version: String): NpmRange =
|
||||||
|
lteq(Version.fromString(version))
|
||||||
|
|
||||||
|
private fun lteq(version: Version): NpmRange =
|
||||||
|
NpmRange(
|
||||||
|
endVersion = version.toSemVer(),
|
||||||
|
endInclusive = true
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun gt(version: String): NpmRange =
|
||||||
|
gt(Version.fromString(version))
|
||||||
|
|
||||||
|
private fun gt(version: Version): NpmRange =
|
||||||
|
NpmRange(
|
||||||
|
startVersion = version.toSemVer()
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun gteq(version: String): NpmRange =
|
||||||
|
gteq(Version.fromString(version))
|
||||||
|
|
||||||
|
private fun gteq(version: Version): NpmRange =
|
||||||
|
NpmRange(
|
||||||
|
startVersion = version.toSemVer(),
|
||||||
|
startInclusive = true
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun eq(version: String): NpmRange =
|
||||||
|
eq(Version.fromString(version))
|
||||||
|
|
||||||
|
private fun eq(version: Version): NpmRange =
|
||||||
|
NpmRange(
|
||||||
|
startVersion = version.toSemVer(),
|
||||||
|
startInclusive = true,
|
||||||
|
endVersion = version.toSemVer(),
|
||||||
|
endInclusive = true
|
||||||
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val EQ = "="
|
const val EQ = "="
|
||||||
|
|||||||
+41
-7
@@ -9,9 +9,9 @@ import com.github.gundy.semver4j.generated.grammar.NodeSemverExpressionLexer
|
|||||||
import com.github.gundy.semver4j.generated.grammar.NodeSemverExpressionParser
|
import com.github.gundy.semver4j.generated.grammar.NodeSemverExpressionParser
|
||||||
import org.antlr.v4.runtime.ANTLRInputStream
|
import org.antlr.v4.runtime.ANTLRInputStream
|
||||||
import org.antlr.v4.runtime.CommonTokenStream
|
import org.antlr.v4.runtime.CommonTokenStream
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmVersionInvertedVisitor.Companion.AND
|
import org.gradle.api.InvalidUserDataException
|
||||||
|
|
||||||
fun invertNpmVersion(version: String): String {
|
fun versionToNpmRanges(version: String): List<NpmRange?> {
|
||||||
val lexer = NodeSemverExpressionLexer(ANTLRInputStream(version))
|
val lexer = NodeSemverExpressionLexer(ANTLRInputStream(version))
|
||||||
val tokens = CommonTokenStream(lexer)
|
val tokens = CommonTokenStream(lexer)
|
||||||
val parser = NodeSemverExpressionParser(tokens)
|
val parser = NodeSemverExpressionParser(tokens)
|
||||||
@@ -22,8 +22,42 @@ fun invertNpmVersion(version: String): String {
|
|||||||
fun buildNpmVersion(
|
fun buildNpmVersion(
|
||||||
includedVersions: List<String>,
|
includedVersions: List<String>,
|
||||||
excludedVersions: List<String>
|
excludedVersions: List<String>
|
||||||
): String =
|
): String {
|
||||||
includedVersions
|
val includedRange: NpmRange? = try {
|
||||||
.joinToString(AND) { it.trimIndent() } +
|
includedVersions
|
||||||
excludedVersions
|
.flatMap { versionToNpmRanges(it) }
|
||||||
.joinToString(prefix = AND, separator = AND) { invertNpmVersion(it.trimIndent()) }
|
.onEach {
|
||||||
|
if (it == null) {
|
||||||
|
throw InvalidUserDataException("Problem with parsing of included versions $includedVersions")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filterNotNull()
|
||||||
|
.reduce { acc: NpmRange, next: NpmRange ->
|
||||||
|
val intersection = acc intersect next
|
||||||
|
requireNotNull(intersection) {
|
||||||
|
"Included versions have no intersection $includedVersions"
|
||||||
|
}
|
||||||
|
intersection!!
|
||||||
|
}
|
||||||
|
} catch (e: UnsupportedOperationException) {
|
||||||
|
throw InvalidUserDataException("No ranges for included versions $includedVersions")
|
||||||
|
}
|
||||||
|
|
||||||
|
includedRange!!
|
||||||
|
|
||||||
|
val excludedRanges: List<NpmRange> = try {
|
||||||
|
excludedVersions
|
||||||
|
.flatMap { versionToNpmRanges(it) }
|
||||||
|
.mapNotNull { it?.invert() }
|
||||||
|
.reduce { acc, next -> acc intersect next }
|
||||||
|
} catch (e: UnsupportedOperationException) {
|
||||||
|
throw InvalidUserDataException("No ranges for excluded versions $excludedVersions")
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (excludedRanges.isEmpty()) {
|
||||||
|
includedRange.toString()
|
||||||
|
} else
|
||||||
|
excludedRanges
|
||||||
|
.mapNotNull { it intersect includedRange }
|
||||||
|
.joinToString(NpmVersionInvertedVisitor.OR)
|
||||||
|
}
|
||||||
+2
-2
@@ -178,8 +178,8 @@ fun Version.toSemVer(): SemVer =
|
|||||||
major.toBigInteger(),
|
major.toBigInteger(),
|
||||||
minor.toBigInteger(),
|
minor.toBigInteger(),
|
||||||
patch.toBigInteger(),
|
patch.toBigInteger(),
|
||||||
preRelease = preReleaseIdentifiers.joinToString("."),
|
preRelease = preReleaseIdentifiers.joinToString(".").let { if (it.isNotEmpty()) it else null },
|
||||||
build = buildIdentifiers.joinToString(".")
|
build = buildIdentifiers.joinToString(".").let { if (it.isNotEmpty()) it else null }
|
||||||
)
|
)
|
||||||
|
|
||||||
fun min(a: SemVer?, b: SemVer?): SemVer? {
|
fun min(a: SemVer?, b: SemVer?): SemVer? {
|
||||||
|
|||||||
Reference in New Issue
Block a user