Browse Source

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
pull/1502/head
Abasov Akif 3 years ago committed by GitHub
parent
commit
43a16c8e77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/CSSRules.kt
  2. 12
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/StyleSheet.kt
  3. 24
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/selectors/CSSSelectors.kt
  4. 17
      web/core/src/jsTest/kotlin/CSSStylesheetTests.kt

2
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/CSSRules.kt

@ -22,7 +22,7 @@ data class CSSStyleRuleDeclaration(
override val style: StyleHolder override val style: StyleHolder
) : CSSRuleDeclaration, CSSStyledRuleDeclaration { ) : CSSRuleDeclaration, CSSStyledRuleDeclaration {
override val header override val header
get() = selector.toString() get() = selector.asString()
} }
interface CSSGroupingRuleDeclaration: CSSRuleDeclaration { interface CSSGroupingRuleDeclaration: CSSRuleDeclaration {

12
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/StyleSheet.kt

@ -79,8 +79,9 @@ open class StyleSheet(
} }
@Suppress("EqualsOrHashCode") @Suppress("EqualsOrHashCode")
class CSSSelfSelector(var selector: CSSSelector? = null) : CSSSelector() { internal class CSSSelfSelector(var selector: CSSSelector? = null) : CSSSelector() {
override fun toString(): String = selector.toString() override fun toString(): String = throw IllegalStateException("You can't concatenate `String + CSSSelector` which contains `self` or `root`. Use `selector(<your string>)` 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 { override fun equals(other: Any?): Boolean {
return other is CSSSelfSelector return other is CSSSelfSelector
} }
@ -157,7 +158,12 @@ fun buildCSS(
cssRule: CSSBuilder.() -> Unit cssRule: CSSBuilder.() -> Unit
): Pair<StyleHolder, CSSRuleDeclarationList> { ): Pair<StyleHolder, CSSRuleDeclarationList> {
val styleSheet = StyleSheetBuilderImpl() 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() builder.cssRule()
return builder to styleSheet.cssRules return builder to styleSheet.cssRules
} }

24
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 { 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 { internal open fun contains(other: CSSSelector, strict: Boolean = false): Boolean {
return if (strict) this === other else this == other 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() { data class Raw(val selector: String) : CSSSelector() {
override fun toString(): String = selector override fun toString(): String = selector
} }
@ -77,6 +82,7 @@ open class CSSSelector {
contains(this, other, selectors, strict) contains(this, other, selectors, strict)
override fun toString(): String = selectors.joinToString("") override fun toString(): String = selectors.joinToString("")
override fun asString(): String = selectors.joinToString("") { it.asString() }
} }
data class Group(val selectors: List<CSSSelector>) : CSSSelector() { data class Group(val selectors: List<CSSSelector>) : CSSSelector() {
@ -84,6 +90,7 @@ open class CSSSelector {
contains(this, other, selectors, strict) contains(this, other, selectors, strict)
override fun toString(): String = selectors.joinToString(", ") override fun toString(): String = selectors.joinToString(", ")
override fun asString(): String = selectors.joinToString(", ") { it.asString() }
} }
data class Descendant(val parent: CSSSelector, val selected: CSSSelector) : CSSSelector() { data class Descendant(val parent: CSSSelector, val selected: CSSSelector) : CSSSelector() {
@ -91,6 +98,7 @@ open class CSSSelector {
contains(this, other, listOf(parent, selected), strict) contains(this, other, listOf(parent, selected), strict)
override fun toString(): String = "$parent $selected" override fun toString(): String = "$parent $selected"
override fun asString(): String = "${parent.asString()} ${selected.asString()}"
} }
data class Child(val parent: CSSSelector, val selected: CSSSelector) : CSSSelector() { data class Child(val parent: CSSSelector, val selected: CSSSelector) : CSSSelector() {
@ -98,6 +106,7 @@ open class CSSSelector {
contains(this, other, listOf(parent, selected), strict) contains(this, other, listOf(parent, selected), strict)
override fun toString(): String = "$parent > $selected" override fun toString(): String = "$parent > $selected"
override fun asString(): String = "${parent.asString()} > ${selected.asString()}"
} }
data class Sibling(val prev: CSSSelector, val selected: CSSSelector) : CSSSelector() { data class Sibling(val prev: CSSSelector, val selected: CSSSelector) : CSSSelector() {
@ -105,6 +114,7 @@ open class CSSSelector {
contains(this, other, listOf(prev, selected), strict) contains(this, other, listOf(prev, selected), strict)
override fun toString(): String = "$prev ~ $selected" override fun toString(): String = "$prev ~ $selected"
override fun asString(): String = "${prev.asString()} ~ ${selected.asString()}"
} }
data class Adjacent(val prev: CSSSelector, val selected: CSSSelector) : CSSSelector() { data class Adjacent(val prev: CSSSelector, val selected: CSSSelector) : CSSSelector() {
@ -112,6 +122,7 @@ open class CSSSelector {
contains(this, other, listOf(prev, selected), strict) contains(this, other, listOf(prev, selected), strict)
override fun toString(): String = "$prev + $selected" override fun toString(): String = "$prev + $selected"
override fun asString(): String = "${prev.asString()} + ${selected.asString()}"
} }
open class PseudoClass(val name: String) : CSSSelector() { open class PseudoClass(val name: String) : CSSSelector() {
@ -202,7 +213,7 @@ open class CSSSelector {
override fun contains(other: CSSSelector, strict: Boolean): Boolean = override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(selector), strict) contains(this, other, listOf(selector), strict)
override fun argsStr() = "$selector" override fun argsStr() = "${selector.asString()}"
} }
// Etc // Etc
@ -238,7 +249,7 @@ open class CSSSelector {
override fun contains(other: CSSSelector, strict: Boolean): Boolean = override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(selector), strict) 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 selector(selector: String) = CSSSelector.Raw(selector)
fun combine(vararg selectors: CSSSelector) = CSSSelector.Combine(selectors.toMutableList()) fun combine(vararg selectors: CSSSelector) = CSSSelector.Combine(selectors.toMutableList())
operator fun CSSSelector.plus(selector: CSSSelector) = combine(this, selector) 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: String) = combine(this, selector(selector))
operator fun CSSSelector.plus(selector: CSSSelector.Combine): CSSSelector.Combine { operator fun CSSSelector.plus(selector: CSSSelector.Combine): CSSSelector.Combine {
selector.selectors.add(0, this) selector.selectors.add(0, this)
return selector 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 { operator fun CSSSelector.Combine.plus(selector: CSSSelector): CSSSelector.Combine {
this.selectors.add(selector) this.selectors.add(selector)
return this return this

17
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.jetbrains.compose.web.dom.stringPresentation
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
import org.w3c.dom.get import org.w3c.dom.get
import kotlin.test.Test
import kotlin.test.assertEquals
import org.jetbrains.compose.web.testutils.* import org.jetbrains.compose.web.testutils.*
import kotlin.test.assertContains import kotlin.test.*
object AppCSSVariables { object AppCSSVariables {
val width by variable<CSSUnitValue>() val width by variable<CSSUnitValue>()
@ -311,4 +309,17 @@ class CSSVariableTests {
"Sibling selector isn't generated correctly" "Sibling selector isn't generated correctly"
) )
} }
@Test
fun testStringPlusCSSSelectorConcatenation() {
assertFailsWith<IllegalStateException>("Concatenation of String + CSSSelector should be restricted.") {
object : StyleSheet() {
val myClass by style {
("h1" + self) {
color(Color.green)
}
}
}
}
}
} }

Loading…
Cancel
Save