[Gradle, JS] Migrate on set for npm ranges

^KT-41054 fixed
This commit is contained in:
Ilya Goncharov
2020-08-07 16:28:25 +03:00
parent 1dd92f011c
commit 9df604cb3d
5 changed files with 62 additions and 63 deletions
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.NpmRangeVisitor.Companion.GT
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmRangeVisitor.Companion.GTEQ import org.jetbrains.kotlin.gradle.targets.js.npm.NpmRangeVisitor.Companion.GTEQ
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmRangeVisitor.Companion.LT import org.jetbrains.kotlin.gradle.targets.js.npm.NpmRangeVisitor.Companion.LT
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmRangeVisitor.Companion.LTEQ import org.jetbrains.kotlin.gradle.targets.js.npm.NpmRangeVisitor.Companion.LTEQ
import org.jetbrains.kotlin.gradle.utils.toListOrEmpty import org.jetbrains.kotlin.gradle.utils.toSetOrEmpty
/** /**
[startVersion] or [endVersion] equaling null means Infinite on appropriate edge, [startVersion] or [endVersion] equaling null means Infinite on appropriate edge,
@@ -47,8 +47,8 @@ data class NpmRange(
} }
} }
infix fun NpmRange.union(other: NpmRange): List<NpmRange> { infix fun NpmRange.union(other: NpmRange): Set<NpmRange> {
if (!hasIntersection(other)) return listOf(this, other) if (!hasIntersection(other)) return setOf(this, other)
val startVersion = minStart(this, other) val startVersion = minStart(this, other)
@@ -59,13 +59,13 @@ infix fun NpmRange.union(other: NpmRange): List<NpmRange> {
startInclusive = if (startVersion == other.startVersion) other.startInclusive else this.startInclusive, startInclusive = if (startVersion == other.startVersion) other.startInclusive else this.startInclusive,
endVersion = endVersion, endVersion = endVersion,
endInclusive = if (endVersion == other.endVersion) other.endInclusive else this.endInclusive endInclusive = if (endVersion == other.endVersion) other.endInclusive else this.endInclusive
).toListOrEmpty() ).toSetOrEmpty()
} }
fun NpmRange.invert(): List<NpmRange> { fun NpmRange.invert(): Set<NpmRange> {
if (startVersion == null && endVersion == null) return emptyList() if (startVersion == null && endVersion == null) return emptySet()
val result = mutableListOf<NpmRange>() val result = mutableSetOf<NpmRange>()
if (startVersion != null || endVersion == null) { if (startVersion != null || endVersion == null) {
result.add( result.add(
NpmRange( NpmRange(
@@ -84,10 +84,10 @@ fun NpmRange.invert(): List<NpmRange> {
) )
} }
return result.distinct() return result
} }
infix fun List<NpmRange>.intersect(others: List<NpmRange>): List<NpmRange> = flatMap { current -> infix fun Set<NpmRange>.intersect(others: Set<NpmRange>): Set<NpmRange> = flatMapTo(mutableSetOf()) { current ->
others.mapNotNull { other -> others.mapNotNull { other ->
current intersect other current intersect other
} }
@@ -9,16 +9,16 @@ import com.github.gundy.semver4j.generated.grammar.NodeSemverExpressionBaseVisit
import com.github.gundy.semver4j.generated.grammar.NodeSemverExpressionParser 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
import org.jetbrains.kotlin.gradle.utils.toListOrEmpty import org.jetbrains.kotlin.gradle.utils.toSetOrEmpty
class NpmRangeVisitor : NodeSemverExpressionBaseVisitor<List<NpmRange>>() { class NpmRangeVisitor : NodeSemverExpressionBaseVisitor<Set<NpmRange>>() {
override fun visitEmptyRange(ctx: NodeSemverExpressionParser.EmptyRangeContext): List<NpmRange> = override fun visitEmptyRange(ctx: NodeSemverExpressionParser.EmptyRangeContext): Set<NpmRange> =
listOf(NpmRange()) setOf(NpmRange())
override fun visitWildcard(ctx: NodeSemverExpressionParser.WildcardContext): List<NpmRange> = override fun visitWildcard(ctx: NodeSemverExpressionParser.WildcardContext): Set<NpmRange> =
listOf(NpmRange()) setOf(NpmRange())
override fun visitWildcardRange(ctx: NodeSemverExpressionParser.WildcardRangeContext): List<NpmRange> { override fun visitWildcardRange(ctx: NodeSemverExpressionParser.WildcardRangeContext): Set<NpmRange> {
val partialWildcardSemver = ctx.partialWildcardSemver() val partialWildcardSemver = ctx.partialWildcardSemver()
val versionText = partialWildcardSemver.text val versionText = partialWildcardSemver.text
val version = versionText val version = versionText
@@ -34,10 +34,10 @@ class NpmRangeVisitor : NodeSemverExpressionBaseVisitor<List<NpmRange>>() {
} }
return (gteq(version) intersect lt(nextVersion)) return (gteq(version) intersect lt(nextVersion))
.toListOrEmpty() .toSetOrEmpty()
} }
override fun visitOperator(ctx: NodeSemverExpressionParser.OperatorContext): List<NpmRange> { override fun visitOperator(ctx: NodeSemverExpressionParser.OperatorContext): Set<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()
@@ -45,54 +45,54 @@ class NpmRangeVisitor : NodeSemverExpressionBaseVisitor<List<NpmRange>>() {
val version = ctx.partialWildcardSemver().text val version = ctx.partialWildcardSemver().text
if (gt == null && lt == null) { if (gt == null && lt == null) {
return listOf(eq(version)) return setOf(eq(version))
} }
val eqToken = eq != null val eqToken = eq != null
if (lt != null) { if (lt != null) {
return listOf( return setOf(
if (eqToken) lteq(version) else lt(version) if (eqToken) lteq(version) else lt(version)
) )
} }
return listOf( return setOf(
if (eqToken) gteq(version) else gt(version) if (eqToken) gteq(version) else gt(version)
) )
} }
override fun visitWildcardOperator(ctx: NodeSemverExpressionParser.WildcardOperatorContext): List<NpmRange> = override fun visitWildcardOperator(ctx: NodeSemverExpressionParser.WildcardOperatorContext): Set<NpmRange> =
listOf(NpmRange()) setOf(NpmRange())
override fun visitTildeRange(ctx: NodeSemverExpressionParser.TildeRangeContext): List<NpmRange> { override fun visitTildeRange(ctx: NodeSemverExpressionParser.TildeRangeContext): Set<NpmRange> {
val version = Version.fromString(ctx.fullSemver().text) val version = Version.fromString(ctx.fullSemver().text)
val nextVersion = version val nextVersion = version
.incrementMinor() .incrementMinor()
return (gteq(version) intersect lt(nextVersion)) return (gteq(version) intersect lt(nextVersion))
.toListOrEmpty() .toSetOrEmpty()
} }
override fun visitCaretRange(ctx: NodeSemverExpressionParser.CaretRangeContext): List<NpmRange> { override fun visitCaretRange(ctx: NodeSemverExpressionParser.CaretRangeContext): Set<NpmRange> {
val version = Version.fromString(ctx.fullSemver().text) val version = Version.fromString(ctx.fullSemver().text)
val nextVersion = version val nextVersion = version
.incrementMajor() .incrementMajor()
return (gteq(version) intersect lt(nextVersion)) return (gteq(version) intersect lt(nextVersion))
.toListOrEmpty() .toSetOrEmpty()
} }
override fun visitFullySpecifiedSemver(ctx: NodeSemverExpressionParser.FullySpecifiedSemverContext): List<NpmRange> = override fun visitFullySpecifiedSemver(ctx: NodeSemverExpressionParser.FullySpecifiedSemverContext): Set<NpmRange> =
visitFullSemver(ctx.fullSemver()) visitFullSemver(ctx.fullSemver())
override fun visitFullSemver(ctx: NodeSemverExpressionParser.FullSemverContext): List<NpmRange> = override fun visitFullSemver(ctx: NodeSemverExpressionParser.FullSemverContext): Set<NpmRange> =
version(ctx.text) version(ctx.text)
override fun visitHyphenatedRangeOfFullySpecifiedVersions(ctx: NodeSemverExpressionParser.HyphenatedRangeOfFullySpecifiedVersionsContext): List<NpmRange> = override fun visitHyphenatedRangeOfFullySpecifiedVersions(ctx: NodeSemverExpressionParser.HyphenatedRangeOfFullySpecifiedVersionsContext): Set<NpmRange> =
(gteq(ctx.left.text) intersect lteq(ctx.right.text)) (gteq(ctx.left.text) intersect lteq(ctx.right.text))
.toListOrEmpty() .toSetOrEmpty()
override fun visitLogicalAndOfSimpleExpressions(ctx: NodeSemverExpressionParser.LogicalAndOfSimpleExpressionsContext): List<NpmRange> = override fun visitLogicalAndOfSimpleExpressions(ctx: NodeSemverExpressionParser.LogicalAndOfSimpleExpressionsContext): Set<NpmRange> =
try { try {
ctx.simple() ctx.simple()
.flatMap { visit(it) } .flatMap { visit(it) }
@@ -102,23 +102,22 @@ class NpmRangeVisitor : NodeSemverExpressionBaseVisitor<List<NpmRange>>() {
} }
} catch (e: UnsupportedOperationException) { } catch (e: UnsupportedOperationException) {
null null
}.toListOrEmpty() }.toSetOrEmpty()
override fun visitLogicalOrOfMultipleRanges(ctx: NodeSemverExpressionParser.LogicalOrOfMultipleRangesContext): List<NpmRange> = override fun visitLogicalOrOfMultipleRanges(ctx: NodeSemverExpressionParser.LogicalOrOfMultipleRangesContext): Set<NpmRange> =
ctx.basicRange() ctx.basicRange()
.flatMap { visitBasicRange(it) } .flatMap { visitBasicRange(it) }
.fold(listOf()) { ranges, range -> .fold(setOf()) { ranges, range ->
if (ranges.isEmpty()) listOf(range) if (ranges.isEmpty()) setOf(range)
else ranges else ranges
.flatMap { it union range } .flatMapTo(mutableSetOf()) { it union range }
} }
private fun version(version: String): List<NpmRange> = private fun version(version: String): Set<NpmRange> =
version(Version.fromString(version)) version(Version.fromString(version))
private fun version(version: Version): List<NpmRange> = private fun version(version: Version): Set<NpmRange> =
(gteq(version) intersect lteq(version)).toListOrEmpty() (gteq(version) intersect lteq(version)).toSetOrEmpty()
private fun lt(version: String): NpmRange = private fun lt(version: String): NpmRange =
lt(Version.fromString(version)) lt(Version.fromString(version))
@@ -11,7 +11,7 @@ import org.antlr.v4.runtime.ANTLRInputStream
import org.antlr.v4.runtime.CommonTokenStream import org.antlr.v4.runtime.CommonTokenStream
import org.gradle.api.InvalidUserDataException import org.gradle.api.InvalidUserDataException
fun versionToNpmRanges(version: String): List<NpmRange> { fun versionToNpmRanges(version: String): Set<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)
@@ -43,7 +43,7 @@ fun buildNpmVersion(
if (excludedVersions.isEmpty()) return includedRange.toString() if (excludedVersions.isEmpty()) return includedRange.toString()
val excludedRanges: List<NpmRange> = try { val excludedRanges: Set<NpmRange> = try {
excludedVersions excludedVersions
.flatMap { versionToNpmRanges(it) } .flatMap { versionToNpmRanges(it) }
.map { it.invert() } .map { it.invert() }
@@ -5,5 +5,5 @@
package org.jetbrains.kotlin.gradle.utils package org.jetbrains.kotlin.gradle.utils
fun <T : Any> T?.toListOrEmpty(): List<T> = fun <T : Any> T?.toSetOrEmpty(): Set<T> =
if (this == null) emptyList() else listOf(this) if (this == null) emptySet() else setOf(this)
@@ -89,26 +89,26 @@ class NpmRangeTest {
@Test @Test
fun unionTest() { fun unionTest() {
fun assertUnion(range1: NpmRange, range2: NpmRange, expected: List<NpmRange>) { fun assertUnion(range1: NpmRange, range2: NpmRange, expected: Set<NpmRange>) {
val union = (range1 union range2) val union = (range1 union range2)
assertTrue("Range $range1 and $range2 expected to have union $expected, but actual is $union") { assertTrue("Range $range1 and $range2 expected to have union $expected, but actual is $union") {
union.toSet() == expected.toSet() union == expected
} }
val symUnion = range2 union range1 val symUnion = range2 union range1
assertTrue("Range $range2 and $range1 expected to have union $expected, but actual is $symUnion") { assertTrue("Range $range2 and $range1 expected to have union $expected, but actual is $symUnion") {
symUnion.toSet() == expected.toSet() symUnion == expected
} }
} }
val range1 = npmRange(startMajor = 1, endMajor = 2) val range1 = npmRange(startMajor = 1, endMajor = 2)
val range2 = npmRange(startMajor = 3, endMajor = 4) val range2 = npmRange(startMajor = 3, endMajor = 4)
assertUnion(range1, range2, listOf(range1, range2)) assertUnion(range1, range2, setOf(range1, range2))
assertUnion( assertUnion(
npmRange(startMajor = 1, endMajor = 3), npmRange(startMajor = 1, endMajor = 3),
npmRange(startMajor = 2, endMajor = 4), npmRange(startMajor = 2, endMajor = 4),
listOf( setOf(
npmRange( npmRange(
startMajor = 1, startMajor = 1,
endMajor = 4 endMajor = 4
@@ -119,7 +119,7 @@ class NpmRangeTest {
assertUnion( assertUnion(
npmRange(startMajor = 1, endMajor = 3), npmRange(startMajor = 1, endMajor = 3),
npmRange(startMajor = 2, endMajor = 4, startInclusive = true, endInclusive = true), npmRange(startMajor = 2, endMajor = 4, startInclusive = true, endInclusive = true),
listOf( setOf(
npmRange( npmRange(
startMajor = 1, startMajor = 1,
endMajor = 4, endMajor = 4,
@@ -131,7 +131,7 @@ class NpmRangeTest {
assertUnion( assertUnion(
npmRange(startMajor = 1, endMajor = 3, startInclusive = true, endInclusive = true), npmRange(startMajor = 1, endMajor = 3, startInclusive = true, endInclusive = true),
npmRange(startMajor = 2, endMajor = 4, startInclusive = true, endInclusive = true), npmRange(startMajor = 2, endMajor = 4, startInclusive = true, endInclusive = true),
listOf( setOf(
npmRange( npmRange(
startMajor = 1, startMajor = 1,
endMajor = 4, endMajor = 4,
@@ -144,7 +144,7 @@ class NpmRangeTest {
assertUnion( assertUnion(
npmRange(startMajor = 1, endMajor = 4, startInclusive = true, endInclusive = true), npmRange(startMajor = 1, endMajor = 4, startInclusive = true, endInclusive = true),
npmRange(startMajor = 2, endMajor = 3, startInclusive = true, endInclusive = true), npmRange(startMajor = 2, endMajor = 3, startInclusive = true, endInclusive = true),
listOf( setOf(
npmRange( npmRange(
startMajor = 1, startMajor = 1,
endMajor = 4, endMajor = 4,
@@ -157,7 +157,7 @@ class NpmRangeTest {
assertUnion( assertUnion(
npmRange(startMajor = 1, endMajor = 2), npmRange(startMajor = 1, endMajor = 2),
npmRange(startMajor = 2, endMajor = 3), npmRange(startMajor = 2, endMajor = 3),
listOf( setOf(
npmRange( npmRange(
startMajor = 1, startMajor = 1,
endMajor = 2 endMajor = 2
@@ -172,7 +172,7 @@ class NpmRangeTest {
assertUnion( assertUnion(
npmRange(startMajor = 1, endMajor = 2, endInclusive = true), npmRange(startMajor = 1, endMajor = 2, endInclusive = true),
npmRange(startMajor = 2, endMajor = 3, startInclusive = true), npmRange(startMajor = 2, endMajor = 3, startInclusive = true),
listOf( setOf(
npmRange( npmRange(
startMajor = 1, startMajor = 1,
endMajor = 3 endMajor = 3
@@ -183,23 +183,23 @@ class NpmRangeTest {
@Test @Test
fun rangeInvertTest() { fun rangeInvertTest() {
fun assertInvert(invertible: NpmRange, expected: List<NpmRange>) { fun assertInvert(invertible: NpmRange, expected: Set<NpmRange>) {
val invert = invertible.invert() val invert = invertible.invert()
assertTrue("Inverted $invertible should be $expected but found $invert") { assertTrue("Inverted $invertible should be $expected but found $invert") {
invert.toSet() == expected.toSet() invert == expected
} }
} }
assertInvert(npmRange(), emptyList()) assertInvert(npmRange(), emptySet())
assertInvert(npmRange(endMajor = 1), listOf(npmRange(startMajor = 1, startInclusive = true))) assertInvert(npmRange(endMajor = 1), setOf(npmRange(startMajor = 1, startInclusive = true)))
assertInvert(npmRange(startMajor = 1), listOf(npmRange(endMajor = 1, endInclusive = true))) assertInvert(npmRange(startMajor = 1), setOf(npmRange(endMajor = 1, endInclusive = true)))
assertInvert(npmRange(endMajor = 1, endInclusive = true), listOf(npmRange(startMajor = 1))) assertInvert(npmRange(endMajor = 1, endInclusive = true), setOf(npmRange(startMajor = 1)))
assertInvert(npmRange(startMajor = 1, startInclusive = true), listOf(npmRange(endMajor = 1))) assertInvert(npmRange(startMajor = 1, startInclusive = true), setOf(npmRange(endMajor = 1)))
assertInvert( assertInvert(
npmRange(startMajor = 1, endMajor = 2), npmRange(startMajor = 1, endMajor = 2),
listOf( setOf(
npmRange(endMajor = 1, endInclusive = true), npmRange(endMajor = 1, endInclusive = true),
npmRange(startMajor = 2, startInclusive = true) npmRange(startMajor = 2, startInclusive = true)
) )