From 43a16c8e77abdf09fa59033d3be9c8c0e57f1afb Mon Sep 17 00:00:00 2001 From: Abasov Akif Date: Mon, 29 Nov 2021 13:37:17 +0300 Subject: [PATCH] Throw exception for `String + CSSSelector` with `self` cases. (#1462) * Throw exception for `String + CSSSelector` with `self` cases. * Refactoring: CSSSelector: open -> abstract, assertTrue -> assertFailsWith * Exceptions rewording * CSSSelfSelector: public -> internal --- .../org/jetbrains/compose/web/css/CSSRules.kt | 2 +- .../jetbrains/compose/web/css/StyleSheet.kt | 12 +++++++--- .../compose/web/css/selectors/CSSSelectors.kt | 24 ++++++++++++------- .../src/jsTest/kotlin/CSSStylesheetTests.kt | 17 ++++++++++--- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/CSSRules.kt b/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/CSSRules.kt index 515a81d42f..e389e3a66c 100644 --- a/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/CSSRules.kt +++ b/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/CSSRules.kt @@ -22,7 +22,7 @@ data class CSSStyleRuleDeclaration( override val style: StyleHolder ) : CSSRuleDeclaration, CSSStyledRuleDeclaration { override val header - get() = selector.toString() + get() = selector.asString() } interface CSSGroupingRuleDeclaration: CSSRuleDeclaration { diff --git a/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/StyleSheet.kt b/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/StyleSheet.kt index ffccd5b32e..6ac77237cd 100644 --- a/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/StyleSheet.kt +++ b/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/StyleSheet.kt @@ -79,8 +79,9 @@ open class StyleSheet( } @Suppress("EqualsOrHashCode") - class CSSSelfSelector(var selector: CSSSelector? = null) : CSSSelector() { - override fun toString(): String = selector.toString() + internal class CSSSelfSelector(var selector: CSSSelector? = null) : CSSSelector() { + override fun toString(): String = throw IllegalStateException("You can't concatenate `String + CSSSelector` which contains `self` or `root`. Use `selector()` to convert `String` to `CSSSelector` for proper work. https://github.com/JetBrains/compose-jb/issues/1440") + override fun asString(): String = selector?.asString() ?: throw IllegalStateException("You can't instantiate self") override fun equals(other: Any?): Boolean { return other is CSSSelfSelector } @@ -157,7 +158,12 @@ fun buildCSS( cssRule: CSSBuilder.() -> Unit ): Pair { val styleSheet = StyleSheetBuilderImpl() - val builder = CSSBuilderImpl(thisClass, thisContext, styleSheet) + // workaround because of problems with plus operator overloading + val root = if (thisClass is StyleSheet.CSSSelfSelector) thisClass else StyleSheet.CSSSelfSelector(thisClass) + // workaround because of problems with plus operator overloading + val self = if (thisContext is StyleSheet.CSSSelfSelector) thisContext else StyleSheet.CSSSelfSelector(thisContext) + + val builder = CSSBuilderImpl(root, self, styleSheet) builder.cssRule() return builder to styleSheet.cssRules } diff --git a/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/selectors/CSSSelectors.kt b/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/selectors/CSSSelectors.kt index a8532d1173..075447b9fa 100644 --- a/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/selectors/CSSSelectors.kt +++ b/web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/selectors/CSSSelectors.kt @@ -21,15 +21,20 @@ sealed class Nth { } } -open class CSSSelector { +abstract class CSSSelector { override fun equals(other: Any?): Boolean { - return this === other || toString() == other.toString() + return this === other || asString() == (other as? CSSSelector)?.asString() } internal open fun contains(other: CSSSelector, strict: Boolean = false): Boolean { return if (strict) this === other else this == other } + // This method made for workaround because of possible concatenation of `String + CSSSelector`, + // so `toString` is called for such operator, but we are calling `asString` for instantiation. + // `toString` is reloaded for CSSSelfSelector + internal open fun asString(): String = toString() + data class Raw(val selector: String) : CSSSelector() { override fun toString(): String = selector } @@ -77,6 +82,7 @@ open class CSSSelector { contains(this, other, selectors, strict) override fun toString(): String = selectors.joinToString("") + override fun asString(): String = selectors.joinToString("") { it.asString() } } data class Group(val selectors: List) : CSSSelector() { @@ -84,6 +90,7 @@ open class CSSSelector { contains(this, other, selectors, strict) override fun toString(): String = selectors.joinToString(", ") + override fun asString(): String = selectors.joinToString(", ") { it.asString() } } data class Descendant(val parent: CSSSelector, val selected: CSSSelector) : CSSSelector() { @@ -91,6 +98,7 @@ open class CSSSelector { contains(this, other, listOf(parent, selected), strict) override fun toString(): String = "$parent $selected" + override fun asString(): String = "${parent.asString()} ${selected.asString()}" } data class Child(val parent: CSSSelector, val selected: CSSSelector) : CSSSelector() { @@ -98,6 +106,7 @@ open class CSSSelector { contains(this, other, listOf(parent, selected), strict) override fun toString(): String = "$parent > $selected" + override fun asString(): String = "${parent.asString()} > ${selected.asString()}" } data class Sibling(val prev: CSSSelector, val selected: CSSSelector) : CSSSelector() { @@ -105,6 +114,7 @@ open class CSSSelector { contains(this, other, listOf(prev, selected), strict) override fun toString(): String = "$prev ~ $selected" + override fun asString(): String = "${prev.asString()} ~ ${selected.asString()}" } data class Adjacent(val prev: CSSSelector, val selected: CSSSelector) : CSSSelector() { @@ -112,6 +122,7 @@ open class CSSSelector { contains(this, other, listOf(prev, selected), strict) override fun toString(): String = "$prev + $selected" + override fun asString(): String = "${prev.asString()} + ${selected.asString()}" } open class PseudoClass(val name: String) : CSSSelector() { @@ -202,7 +213,7 @@ open class CSSSelector { override fun contains(other: CSSSelector, strict: Boolean): Boolean = contains(this, other, listOf(selector), strict) - override fun argsStr() = "$selector" + override fun argsStr() = "${selector.asString()}" } // Etc @@ -238,7 +249,7 @@ open class CSSSelector { override fun contains(other: CSSSelector, strict: Boolean): Boolean = contains(this, other, listOf(selector), strict) - override fun argsStr() = selector.toString() + override fun argsStr() = selector.asString() } } } @@ -246,16 +257,11 @@ open class CSSSelector { fun selector(selector: String) = CSSSelector.Raw(selector) fun combine(vararg selectors: CSSSelector) = CSSSelector.Combine(selectors.toMutableList()) operator fun CSSSelector.plus(selector: CSSSelector) = combine(this, selector) -operator fun String.plus(selector: CSSSelector) = combine(selector(this), selector) operator fun CSSSelector.plus(selector: String) = combine(this, selector(selector)) operator fun CSSSelector.plus(selector: CSSSelector.Combine): CSSSelector.Combine { selector.selectors.add(0, this) return selector } -operator fun String.plus(selector: CSSSelector.Combine): CSSSelector.Combine { - selector.selectors.add(0, selector(this)) - return selector -} operator fun CSSSelector.Combine.plus(selector: CSSSelector): CSSSelector.Combine { this.selectors.add(selector) return this diff --git a/web/core/src/jsTest/kotlin/CSSStylesheetTests.kt b/web/core/src/jsTest/kotlin/CSSStylesheetTests.kt index f529985f90..99aae72382 100644 --- a/web/core/src/jsTest/kotlin/CSSStylesheetTests.kt +++ b/web/core/src/jsTest/kotlin/CSSStylesheetTests.kt @@ -13,10 +13,8 @@ import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.stringPresentation import org.w3c.dom.HTMLElement import org.w3c.dom.get -import kotlin.test.Test -import kotlin.test.assertEquals import org.jetbrains.compose.web.testutils.* -import kotlin.test.assertContains +import kotlin.test.* object AppCSSVariables { val width by variable() @@ -311,4 +309,17 @@ class CSSVariableTests { "Sibling selector isn't generated correctly" ) } + + @Test + fun testStringPlusCSSSelectorConcatenation() { + assertFailsWith("Concatenation of String + CSSSelector should be restricted.") { + object : StyleSheet() { + val myClass by style { + ("h1" + self) { + color(Color.green) + } + } + } + } + } }