Browse Source

Make all CSS Selectors private (#1519)

pull/1523/head
Shagen Ogandzhanian 3 years ago committed by GitHub
parent
commit
d902912424
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 301
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/StyleSheetBuilder.kt
  2. 270
      web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/selectors/CSSSelectors.kt

301
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/StyleSheetBuilder.kt

@ -1,7 +1,6 @@
package org.jetbrains.compose.web.css package org.jetbrains.compose.web.css
import org.jetbrains.compose.web.css.selectors.CSSSelector import org.jetbrains.compose.web.css.selectors.*
import org.jetbrains.compose.web.css.selectors.Nth
interface CSSRulesHolder { interface CSSRulesHolder {
val cssRules: CSSRuleDeclarationList val cssRules: CSSRuleDeclarationList
@ -27,24 +26,24 @@ interface GenericStyleSheetBuilder<TBuilder> : CSSRulesHolder, SelectorsScope {
} }
operator fun String.invoke(cssRule: TBuilder.() -> Unit) { operator fun String.invoke(cssRule: TBuilder.() -> Unit) {
style(CSSSelector.Raw(this), cssRule) style(Raw(this), cssRule)
} }
infix fun String.style(cssRule: TBuilder.() -> Unit) { infix fun String.style(cssRule: TBuilder.() -> Unit) {
style(CSSSelector.Raw(this), cssRule) style(Raw(this), cssRule)
} }
} }
interface SelectorsScope { interface SelectorsScope {
fun selector(selector: String): CSSSelector = CSSSelector.Raw(selector) fun selector(selector: String): CSSSelector = Raw(selector)
fun combine(vararg selectors: CSSSelector): CSSSelector = CSSSelector.Combine(selectors.toMutableList()) fun combine(vararg selectors: CSSSelector): CSSSelector = Combine(selectors.toMutableList())
operator fun CSSSelector.plus(selector: CSSSelector): CSSSelector { operator fun CSSSelector.plus(selector: CSSSelector): CSSSelector {
if (this is CSSSelector.Combine) { if (this is Combine) {
this.selectors.add(selector) this.selectors.add(selector)
return this return this
} }
return if (selector is CSSSelector.Combine) { return if (selector is Combine) {
selector.selectors.add(0, this) selector.selectors.add(0, this)
selector selector
} else { } else {
@ -53,7 +52,7 @@ interface SelectorsScope {
} }
operator fun CSSSelector.plus(selector: String): CSSSelector { operator fun CSSSelector.plus(selector: String): CSSSelector {
if (this is CSSSelector.Combine) { if (this is Combine) {
this.selectors.add(selector(selector)) this.selectors.add(selector(selector))
return this return this
} }
@ -63,21 +62,21 @@ interface SelectorsScope {
@JsName("returnUniversalSelector") @JsName("returnUniversalSelector")
@Deprecated("Use universal property", replaceWith = ReplaceWith("universal")) @Deprecated("Use universal property", replaceWith = ReplaceWith("universal"))
fun universal(): CSSSelector = CSSSelector.Universal fun universal(): CSSSelector = Universal
val universal: CSSSelector val universal: CSSSelector
get() = CSSSelector.Universal get() = Universal
fun type(type: String): CSSSelector = CSSSelector.Type(type) fun type(type: String): CSSSelector = Type(type)
fun className(className: String): CSSSelector = CSSSelector.CSSClass(className) fun className(className: String): CSSSelector = CSSSelector.CSSClass(className)
fun id(id: String): CSSSelector = CSSSelector.Id(id) fun id(id: String): CSSSelector = Id(id)
fun attr( fun attr(
name: String, name: String,
value: String? = null, value: String? = null,
operator: CSSSelector.Attribute.Operator = CSSSelector.Attribute.Operator.Equals, operator: CSSSelector.Attribute.Operator = CSSSelector.Attribute.Operator.Equals,
caseSensitive: Boolean = true caseSensitive: Boolean = true
): CSSSelector = CSSSelector.AttributeInternal(name, value, operator, caseSensitive) ): CSSSelector = Attribute(name, value, operator, caseSensitive)
fun attrEquals(name: String, value: String? = null, caseSensitive: Boolean = true) = fun attrEquals(name: String, value: String? = null, caseSensitive: Boolean = true) =
attr(name, value, CSSSelector.Attribute.Operator.Equals, caseSensitive) attr(name, value, CSSSelector.Attribute.Operator.Equals, caseSensitive)
@ -97,18 +96,18 @@ interface SelectorsScope {
fun attrContains(name: String, value: String? = null, caseSensitive: Boolean = true) = fun attrContains(name: String, value: String? = null, caseSensitive: Boolean = true) =
attr(name, value, CSSSelector.Attribute.Operator.Contains, caseSensitive) attr(name, value, CSSSelector.Attribute.Operator.Contains, caseSensitive)
fun group(vararg selectors: CSSSelector): CSSSelector = CSSSelector.Group(selectors.toList()) fun group(vararg selectors: CSSSelector): CSSSelector = Group(selectors.toList())
@Deprecated("Replaced with `desc`", ReplaceWith("desc(parent, selected)")) @Deprecated("Replaced with `desc`", ReplaceWith("desc(parent, selected)"))
fun descendant(parent: CSSSelector, selected: CSSSelector): CSSSelector = desc(parent, selected) fun descendant(parent: CSSSelector, selected: CSSSelector): CSSSelector = desc(parent, selected)
fun desc(parent: CSSSelector, selected: CSSSelector): CSSSelector = CSSSelector.Descendant(parent, selected) fun desc(parent: CSSSelector, selected: CSSSelector): CSSSelector = Descendant(parent, selected)
fun desc(parent: CSSSelector, selected: String): CSSSelector = desc(parent, selector(selected)) fun desc(parent: CSSSelector, selected: String): CSSSelector = desc(parent, selector(selected))
fun desc(parent: String, selected: CSSSelector): CSSSelector = desc(selector(parent), selected) fun desc(parent: String, selected: CSSSelector): CSSSelector = desc(selector(parent), selected)
fun desc(parent: String, selected: String): CSSSelector = desc(selector(parent), selector(selected)) fun desc(parent: String, selected: String): CSSSelector = desc(selector(parent), selector(selected))
fun child(parent: CSSSelector, selected: CSSSelector): CSSSelector = CSSSelector.Child(parent, selected) fun child(parent: CSSSelector, selected: CSSSelector): CSSSelector = Child(parent, selected)
fun sibling(sibling: CSSSelector, selected: CSSSelector): CSSSelector = CSSSelector.Sibling(sibling, selected) fun sibling(sibling: CSSSelector, selected: CSSSelector): CSSSelector = Sibling(sibling, selected)
fun adjacent(sibling: CSSSelector, selected: CSSSelector): CSSSelector = CSSSelector.Adjacent(sibling, selected) fun adjacent(sibling: CSSSelector, selected: CSSSelector): CSSSelector = Adjacent(sibling, selected)
@JsName("returnHoverSelector") @JsName("returnHoverSelector")
@Deprecated("Use hover property", replaceWith = ReplaceWith("hover")) @Deprecated("Use hover property", replaceWith = ReplaceWith("hover"))
@ -117,131 +116,277 @@ interface SelectorsScope {
// Location pseudo-classes // Location pseudo-classes
val anyLink: CSSSelector val anyLink: CSSSelector
get() = CSSSelector.PseudoClassInternal("any-link") get() = PseudoClassInternal("any-link")
val link: CSSSelector val link: CSSSelector
get() = CSSSelector.PseudoClassInternal("link") get() = PseudoClassInternal("link")
val visited: CSSSelector val visited: CSSSelector
get() = CSSSelector.PseudoClassInternal("visited") get() = PseudoClassInternal("visited")
val localLink: CSSSelector val localLink: CSSSelector
get() = CSSSelector.PseudoClassInternal("local-link") get() = PseudoClassInternal("local-link")
val target: CSSSelector val target: CSSSelector
get() = CSSSelector.PseudoClassInternal("target") get() = PseudoClassInternal("target")
val targetWithin: CSSSelector val targetWithin: CSSSelector
get() = CSSSelector.PseudoClassInternal("target-within") get() = PseudoClassInternal("target-within")
val scope: CSSSelector val scope: CSSSelector
get() = CSSSelector.PseudoClassInternal("scope") get() = PseudoClassInternal("scope")
// User action pseudo-classes // User action pseudo-classes
val hover: CSSSelector val hover: CSSSelector
get() = CSSSelector.PseudoClassInternal("hover") get() = PseudoClassInternal("hover")
val active: CSSSelector val active: CSSSelector
get() = CSSSelector.PseudoClassInternal("active") get() = PseudoClassInternal("active")
val focus: CSSSelector val focus: CSSSelector
get() = CSSSelector.PseudoClassInternal("focus") get() = PseudoClassInternal("focus")
val focusVisible: CSSSelector val focusVisible: CSSSelector
get() = CSSSelector.PseudoClassInternal("focus-visible") get() = PseudoClassInternal("focus-visible")
// Resource state pseudo-classes // Resource state pseudo-classes
val playing: CSSSelector val playing: CSSSelector
get() = CSSSelector.PseudoClassInternal("playing") get() = PseudoClassInternal("playing")
val paused: CSSSelector val paused: CSSSelector
get() = CSSSelector.PseudoClassInternal("paused") get() = PseudoClassInternal("paused")
// The input pseudo-classes // The input pseudo-classes
val autofill: CSSSelector val autofill: CSSSelector
get() = CSSSelector.PseudoClassInternal("autofill") get() = PseudoClassInternal("autofill")
val enabled: CSSSelector val enabled: CSSSelector
get() = CSSSelector.PseudoClassInternal("enabled") get() = PseudoClassInternal("enabled")
val disabled: CSSSelector val disabled: CSSSelector
get() = CSSSelector.PseudoClassInternal("disabled") get() = PseudoClassInternal("disabled")
val readOnly: CSSSelector val readOnly: CSSSelector
get() = CSSSelector.PseudoClassInternal("read-only") get() = PseudoClassInternal("read-only")
val readWrite: CSSSelector val readWrite: CSSSelector
get() = CSSSelector.PseudoClassInternal("read-write") get() = PseudoClassInternal("read-write")
val placeholderShown: CSSSelector val placeholderShown: CSSSelector
get() = CSSSelector.PseudoClassInternal("placeholder-shown") get() = PseudoClassInternal("placeholder-shown")
val default: CSSSelector val default: CSSSelector
get() = CSSSelector.PseudoClassInternal("default") get() = PseudoClassInternal("default")
val checked: CSSSelector val checked: CSSSelector
get() = CSSSelector.PseudoClassInternal("checked") get() = PseudoClassInternal("checked")
val indeterminate: CSSSelector val indeterminate: CSSSelector
get() = CSSSelector.PseudoClassInternal("indeterminate") get() = PseudoClassInternal("indeterminate")
val blank: CSSSelector val blank: CSSSelector
get() = CSSSelector.PseudoClassInternal("blank") get() = PseudoClassInternal("blank")
val valid: CSSSelector val valid: CSSSelector
get() = CSSSelector.PseudoClassInternal("valid") get() = PseudoClassInternal("valid")
val invalid: CSSSelector val invalid: CSSSelector
get() = CSSSelector.PseudoClassInternal("invalid") get() = PseudoClassInternal("invalid")
val inRange: CSSSelector val inRange: CSSSelector
get() = CSSSelector.PseudoClassInternal("in-range") get() = PseudoClassInternal("in-range")
val outOfRange: CSSSelector val outOfRange: CSSSelector
get() = CSSSelector.PseudoClassInternal("out-of-range") get() = PseudoClassInternal("out-of-range")
val required: CSSSelector val required: CSSSelector
get() = CSSSelector.PseudoClassInternal("required") get() = PseudoClassInternal("required")
val optional: CSSSelector val optional: CSSSelector
get() = CSSSelector.PseudoClassInternal("optional") get() = PseudoClassInternal("optional")
val userInvalid: CSSSelector val userInvalid: CSSSelector
get() = CSSSelector.PseudoClassInternal("user-invalid") get() = PseudoClassInternal("user-invalid")
// Tree-structural pseudo-classes // Tree-structural pseudo-classes
val root: CSSSelector val root: CSSSelector
get() = CSSSelector.PseudoClassInternal("root") get() = PseudoClassInternal("root")
val empty: CSSSelector val empty: CSSSelector
get() = CSSSelector.PseudoClassInternal("empty") get() = PseudoClassInternal("empty")
val first: CSSSelector val first: CSSSelector
get() = CSSSelector.PseudoClassInternal("first") get() = PseudoClassInternal("first")
val firstChild: CSSSelector val firstChild: CSSSelector
get() = CSSSelector.PseudoClassInternal("first-child") get() = PseudoClassInternal("first-child")
val lastChild: CSSSelector val lastChild: CSSSelector
get() = CSSSelector.PseudoClassInternal("last-child") get() = PseudoClassInternal("last-child")
val onlyChild: CSSSelector val onlyChild: CSSSelector
get() = CSSSelector.PseudoClassInternal("only-child") get() = PseudoClassInternal("only-child")
val firstOfType: CSSSelector val firstOfType: CSSSelector
get() = CSSSelector.PseudoClassInternal("first-of-type") get() = PseudoClassInternal("first-of-type")
val lastOfType: CSSSelector val lastOfType: CSSSelector
get() = CSSSelector.PseudoClassInternal("last-of-type") get() = PseudoClassInternal("last-of-type")
val onlyOfType: CSSSelector val onlyOfType: CSSSelector
get() = CSSSelector.PseudoClassInternal("only-of-type") get() = PseudoClassInternal("only-of-type")
val host: CSSSelector val host: CSSSelector
get() = CSSSelector.PseudoClassInternal("host") get() = PseudoClassInternal("host")
// Etc // Etc
val defined: CSSSelector val defined: CSSSelector
get() = CSSSelector.PseudoClassInternal("defined") get() = PseudoClassInternal("defined")
val left: CSSSelector val left: CSSSelector
get() = CSSSelector.PseudoClassInternal("left") get() = PseudoClassInternal("left")
val right: CSSSelector val right: CSSSelector
get() = CSSSelector.PseudoClassInternal("right") get() = PseudoClassInternal("right")
fun lang(langCode: LanguageCode): CSSSelector = CSSSelector.PseudoClassInternal.Lang(langCode) fun lang(langCode: LanguageCode): CSSSelector = PseudoClassInternal.Lang(langCode)
fun nthChild(nth: Nth): CSSSelector = CSSSelector.PseudoClassInternal.NthChild(nth) fun nthChild(nth: Nth): CSSSelector = PseudoClassInternal.NthChild(nth)
fun nthLastChild(nth: Nth): CSSSelector = CSSSelector.PseudoClassInternal.NthLastChild(nth) fun nthLastChild(nth: Nth): CSSSelector = PseudoClassInternal.NthLastChild(nth)
fun nthOfType(nth: Nth): CSSSelector = CSSSelector.PseudoClassInternal.NthOfType(nth) fun nthOfType(nth: Nth): CSSSelector = PseudoClassInternal.NthOfType(nth)
fun nthLastOfType(nth: Nth): CSSSelector = CSSSelector.PseudoClassInternal.NthLastOfType(nth) fun nthLastOfType(nth: Nth): CSSSelector = PseudoClassInternal.NthLastOfType(nth)
fun host(selector: CSSSelector): CSSSelector = CSSSelector.PseudoClassInternal.Host(selector) fun host(selector: CSSSelector): CSSSelector = PseudoClassInternal.Host(selector)
fun not(selector: CSSSelector): CSSSelector = CSSSelector.PseudoClassInternal.Not(selector) fun not(selector: CSSSelector): CSSSelector = PseudoClassInternal.Not(selector)
// Pseudo Element // Pseudo Element
val after: CSSSelector val after: CSSSelector
get() = CSSSelector.PseudoElementInternal("after") get() = PseudoElementInternal("after")
val before: CSSSelector val before: CSSSelector
get() = CSSSelector.PseudoElementInternal("before") get() = PseudoElementInternal("before")
val cue: CSSSelector val cue: CSSSelector
get() = CSSSelector.PseudoElementInternal("cue") get() = PseudoElementInternal("cue")
val cueRegion: CSSSelector val cueRegion: CSSSelector
get() = CSSSelector.PseudoElementInternal("cue-region") get() = PseudoElementInternal("cue-region")
val firstLetter: CSSSelector val firstLetter: CSSSelector
get() = CSSSelector.PseudoElementInternal("first-letter") get() = PseudoElementInternal("first-letter")
val firstLine: CSSSelector val firstLine: CSSSelector
get() = CSSSelector.PseudoElementInternal("first-line") get() = PseudoElementInternal("first-line")
val fileSelectorButton: CSSSelector val fileSelectorButton: CSSSelector
get() = CSSSelector.PseudoElementInternal("file-selector-button") get() = PseudoElementInternal("file-selector-button")
val selection: CSSSelector val selection: CSSSelector
get() = CSSSelector.PseudoElementInternal("selection") get() = PseudoElementInternal("selection")
fun slotted(selector: CSSSelector): CSSSelector = CSSSelector.PseudoElementInternal.Slotted(selector) fun slotted(selector: CSSSelector): CSSSelector = PseudoElementInternal.Slotted(selector)
} }
private data class Id(val id: String) : CSSSelector() {
override fun toString(): String = "#$id"
}
private data class Type(val type: String) : CSSSelector() {
override fun toString(): String = type
}
private object Universal : CSSSelector() {
override fun toString(): String = "*"
}
private data class Raw(val selector: String) : CSSSelector() {
override fun toString(): String = selector
}
private data class Combine(val selectors: MutableList<CSSSelector>) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, selectors, strict)
override fun toString(): String = selectors.joinToString("")
override fun asString(): String = selectors.joinToString("") { it.asString() }
}
private data class Group(val selectors: List<CSSSelector>) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, selectors, strict)
override fun toString(): String = selectors.joinToString(", ")
override fun asString(): String = selectors.joinToString(", ") { it.asString() }
}
private data class Descendant(val parent: CSSSelector, val selected: CSSSelector) :
CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(parent, selected), strict)
override fun toString(): String = "$parent $selected"
override fun asString(): String = "${parent.asString()} ${selected.asString()}"
}
private data class Child(val parent: CSSSelector, val selected: CSSSelector) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(parent, selected), strict)
override fun toString(): String = "$parent > $selected"
override fun asString(): String = "${parent.asString()} > ${selected.asString()}"
}
private data class Sibling(val prev: CSSSelector, val selected: CSSSelector) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(prev, selected), strict)
override fun toString(): String = "$prev ~ $selected"
override fun asString(): String = "${prev.asString()} ~ ${selected.asString()}"
}
private data class Adjacent(val prev: CSSSelector, val selected: CSSSelector) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(prev, selected), strict)
override fun toString(): String = "$prev + $selected"
override fun asString(): String = "${prev.asString()} + ${selected.asString()}"
}
private data class Attribute(
val name: String,
val value: String? = null,
val operator: Attribute.Operator = Attribute.Operator.Equals,
val caseSensitive: Boolean = true
) : CSSSelector() {
override fun toString(): String {
val valueStr = value?.let {
"${operator.value}$value${if (!caseSensitive) " i" else ""}"
} ?: ""
return "[$name$valueStr]"
}
}
private open class PseudoClassInternal(val name: String) : CSSSelector() {
override fun equals(other: Any?): Boolean {
return if (other is PseudoClassInternal) {
name == other.name && argsStr() == other.argsStr()
} else false
}
open fun argsStr(): String? = null
override fun toString(): String = ":$name${argsStr()?.let { "($it)" } ?: ""}"
// Linguistic pseudo-classes
class Lang internal constructor(val langCode: LanguageCode) : PseudoClassInternal("lang") {
override fun argsStr() = langCode
}
// Tree-structural pseudo-classes
class NthChild internal constructor(val nth: Nth) : PseudoClassInternal("nth-child") {
override fun argsStr() = "$nth"
}
class NthLastChild internal constructor(val nth: Nth) : PseudoClassInternal("nth-last-child") {
override fun argsStr() = "$nth"
}
class NthOfType internal constructor(val nth: Nth) : PseudoClassInternal("nth-of-type") {
override fun argsStr() = "$nth"
}
class NthLastOfType internal constructor(val nth: Nth) : PseudoClassInternal("nth-last-of-type") {
override fun argsStr() = "$nth"
}
class Host internal constructor(val selector: CSSSelector) : PseudoClassInternal("host") {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(selector), strict)
override fun argsStr() = selector.asString()
}
// Etc
class Not internal constructor(val selector: CSSSelector) : PseudoClassInternal("not") {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(selector), strict)
override fun argsStr() = "$selector"
}
}
private open class PseudoElementInternal(val name: String) : CSSSelector() {
override fun equals(other: Any?): Boolean {
return if (other is PseudoElementInternal) {
name == other.name && argsStr() == other.argsStr()
} else false
}
open fun argsStr(): String? = null
override fun toString(): String = "::$name${argsStr()?.let { "($it)" } ?: ""}"
class Slotted internal constructor(val selector: CSSSelector) : PseudoElementInternal("slotted") {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(selector), strict)
override fun argsStr() = selector.asString()
}
}
interface StyleSheetBuilder : CSSRulesHolder, GenericStyleSheetBuilder<CSSStyleRuleBuilder> { interface StyleSheetBuilder : CSSRulesHolder, GenericStyleSheetBuilder<CSSStyleRuleBuilder> {
override fun style(selector: CSSSelector, cssRule: CSSStyleRuleBuilder.() -> Unit) { override fun style(selector: CSSSelector, cssRule: CSSStyleRuleBuilder.() -> Unit) {
add(selector, buildCSSStyleRule(cssRule)) add(selector, buildCSSStyleRule(cssRule))

270
web/core/src/jsMain/kotlin/org/jetbrains/compose/web/css/selectors/CSSSelectors.kt

@ -2,7 +2,10 @@
package org.jetbrains.compose.web.css.selectors package org.jetbrains.compose.web.css.selectors
import org.jetbrains.compose.web.css.LanguageCode import org.jetbrains.compose.web.css.SelectorsScope
internal const val webCssSelectorsDeprecationMessage = "Consider using a property from SelectorsScope"
private val selectorScope = object : SelectorsScope {}
sealed class Nth { sealed class Nth {
data class Functional(val a: Int? = null, val b: Int? = null) { data class Functional(val a: Int? = null, val b: Int? = null) {
@ -30,31 +33,23 @@ abstract class CSSSelector internal constructor() {
return if (strict) this === other else this == other return if (strict) this === other else this == other
} }
@Suppress("SuspiciousEqualsCombination")
protected fun contains(that: CSSSelector, other: CSSSelector, children: List<CSSSelector>, strict: Boolean): Boolean {
return that === other || // exactly same selector
children.any { it.contains(other, strict) } || // contains it in children
(!strict && that == other) // equals structurally
}
// This method made for workaround because of possible concatenation of `String + CSSSelector`, // 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. // so `toString` is called for such operator, but we are calling `asString` for instantiation.
// `toString` is reloaded for CSSSelfSelector // `toString` is reloaded for CSSSelfSelector
internal open fun asString(): String = toString() internal open fun asString(): String = toString()
internal data class Raw internal constructor(val selector: String) : CSSSelector() {
override fun toString(): String = selector
}
internal object Universal : CSSSelector() {
override fun toString(): String = "*"
}
internal data class Type internal constructor(val type: String) : CSSSelector() {
override fun toString(): String = type
}
internal data class CSSClass internal constructor(val className: String) : CSSSelector() { internal data class CSSClass internal constructor(val className: String) : CSSSelector() {
override fun toString(): String = ".$className" override fun toString(): String = ".$className"
} }
internal data class Id internal constructor(val id: String) : CSSSelector() {
override fun toString(): String = "#$id"
}
object Attribute { object Attribute {
enum class Operator(val value: String) { enum class Operator(val value: String) {
Equals("="), Equals("="),
@ -66,261 +61,122 @@ abstract class CSSSelector internal constructor() {
} }
} }
internal data class AttributeInternal internal constructor(
val name: String,
val value: String? = null,
val operator: Attribute.Operator = Attribute.Operator.Equals,
val caseSensitive: Boolean = true
) : CSSSelector() {
override fun toString(): String {
val valueStr = value?.let {
"${operator.value}$value${if (!caseSensitive) " i" else ""}"
} ?: ""
return "[$name$valueStr]"
}
}
internal data class Combine internal constructor(val selectors: MutableList<CSSSelector>) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, selectors, strict)
override fun toString(): String = selectors.joinToString("")
override fun asString(): String = selectors.joinToString("") { it.asString() }
}
internal data class Group internal constructor(val selectors: List<CSSSelector>) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, selectors, strict)
override fun toString(): String = selectors.joinToString(", ")
override fun asString(): String = selectors.joinToString(", ") { it.asString() }
}
internal data class Descendant internal constructor(val parent: CSSSelector, val selected: CSSSelector) :
CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(parent, selected), strict)
override fun toString(): String = "$parent $selected"
override fun asString(): String = "${parent.asString()} ${selected.asString()}"
}
internal data class Child internal constructor(val parent: CSSSelector, val selected: CSSSelector) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(parent, selected), strict)
override fun toString(): String = "$parent > $selected"
override fun asString(): String = "${parent.asString()} > ${selected.asString()}"
}
internal data class Sibling internal constructor(val prev: CSSSelector, val selected: CSSSelector) : CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(prev, selected), strict)
override fun toString(): String = "$prev ~ $selected"
override fun asString(): String = "${prev.asString()} ~ ${selected.asString()}"
}
internal data class Adjacent internal constructor(val prev: CSSSelector, val selected: CSSSelector) :
CSSSelector() {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(prev, selected), strict)
override fun toString(): String = "$prev + $selected"
override fun asString(): String = "${prev.asString()} + ${selected.asString()}"
}
object PseudoClass { object PseudoClass {
// Location pseudo-classes // Location pseudo-classes
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val anyLink : CSSSelector = PseudoClassInternal("any-link") val anyLink : CSSSelector = selectorScope.anyLink
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val link : CSSSelector = PseudoClassInternal("link") val link : CSSSelector = selectorScope.link
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val visited : CSSSelector = PseudoClassInternal("visited") val visited : CSSSelector = selectorScope.visited
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val localLink : CSSSelector = PseudoClassInternal("local-link") val localLink : CSSSelector = selectorScope.localLink
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val target : CSSSelector = PseudoClassInternal("target") val target : CSSSelector = selectorScope.target
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val targetWithin : CSSSelector = PseudoClassInternal("target-within") val targetWithin : CSSSelector = selectorScope.targetWithin
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val scope : CSSSelector = PseudoClassInternal("scope") val scope : CSSSelector = selectorScope.scope
// User action pseudo-classes // User action pseudo-classes
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val hover : CSSSelector = PseudoClassInternal("hover") val hover : CSSSelector = selectorScope.hover
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val active : CSSSelector = PseudoClassInternal("active") val active : CSSSelector = selectorScope.active
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val focus : CSSSelector = PseudoClassInternal("focus") val focus : CSSSelector = selectorScope.focus
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val focusVisible : CSSSelector = PseudoClassInternal("focus-visible") val focusVisible : CSSSelector = selectorScope.focusVisible
// Resource state pseudo-classes // Resource state pseudo-classes
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val playing : CSSSelector = PseudoClassInternal("playing") val playing : CSSSelector = selectorScope.playing
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val paused : CSSSelector = PseudoClassInternal("paused") val paused : CSSSelector = selectorScope.paused
// The input pseudo-classes // The input pseudo-classes
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val autofill : CSSSelector = PseudoClassInternal("autofill") val autofill : CSSSelector = selectorScope.autofill
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val enabled : CSSSelector = PseudoClassInternal("enabled") val enabled : CSSSelector = selectorScope.enabled
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val disabled : CSSSelector = PseudoClassInternal("disabled") val disabled : CSSSelector = selectorScope.disabled
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val readOnly : CSSSelector = PseudoClassInternal("read-only") val readOnly : CSSSelector = selectorScope.readOnly
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val readWrite : CSSSelector = PseudoClassInternal("read-write") val readWrite : CSSSelector = selectorScope.readWrite
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val placeholderShown : CSSSelector = PseudoClassInternal("placeholder-shown") val placeholderShown : CSSSelector = selectorScope.placeholderShown
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val default : CSSSelector = PseudoClassInternal("default") val default : CSSSelector = selectorScope.default
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val checked : CSSSelector = PseudoClassInternal("checked") val checked : CSSSelector = selectorScope.checked
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val indeterminate : CSSSelector = PseudoClassInternal("indeterminate") val indeterminate : CSSSelector = selectorScope.indeterminate
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val blank : CSSSelector = PseudoClassInternal("blank") val blank : CSSSelector = selectorScope.blank
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val valid : CSSSelector = PseudoClassInternal("valid") val valid : CSSSelector = selectorScope.valid
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val invalid : CSSSelector = PseudoClassInternal("invalid") val invalid : CSSSelector = selectorScope.invalid
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val inRange : CSSSelector = PseudoClassInternal("in-range") val inRange : CSSSelector = selectorScope.invalid
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val outOfRange : CSSSelector = PseudoClassInternal("out-of-range") val outOfRange : CSSSelector = selectorScope.outOfRange
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val required : CSSSelector = PseudoClassInternal("required") val required : CSSSelector = selectorScope.required
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val optional : CSSSelector = PseudoClassInternal("optional") val optional : CSSSelector = selectorScope.optional
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val userInvalid : CSSSelector = PseudoClassInternal("user-invalid") val userInvalid : CSSSelector = selectorScope.userInvalid
// Tree-structural pseudo-classes // Tree-structural pseudo-classes
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val root : CSSSelector = PseudoClassInternal("root") val root : CSSSelector = selectorScope.root
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val empty : CSSSelector = PseudoClassInternal("empty") val empty : CSSSelector = selectorScope.empty
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val first : CSSSelector = PseudoClassInternal("first") val first : CSSSelector = selectorScope.first
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val firstChild : CSSSelector = PseudoClassInternal("first-child") val firstChild : CSSSelector = selectorScope.firstChild
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val lastChild : CSSSelector = PseudoClassInternal("last-child") val lastChild : CSSSelector = selectorScope.lastChild
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val onlyChild : CSSSelector = PseudoClassInternal("only-child") val onlyChild : CSSSelector = selectorScope.onlyChild
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val firstOfType : CSSSelector = PseudoClassInternal("first-of-type") val firstOfType : CSSSelector = selectorScope.firstOfType
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val lastOfType : CSSSelector = PseudoClassInternal("last-of-type") val lastOfType : CSSSelector = selectorScope.lastOfType
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val onlyOfType : CSSSelector = PseudoClassInternal("only-of-type") val onlyOfType : CSSSelector = selectorScope.onlyOfType
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val host : CSSSelector = PseudoClassInternal("host") val host : CSSSelector = selectorScope.host
// Etc // Etc
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val defined : CSSSelector = PseudoClassInternal("defined") val defined : CSSSelector = selectorScope.defined
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val left : CSSSelector = PseudoClassInternal("left") val left : CSSSelector = selectorScope.left
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val right : CSSSelector = PseudoClassInternal("right") val right : CSSSelector = selectorScope.right
}
internal open class PseudoClassInternal internal constructor(val name: String) : CSSSelector() {
override fun equals(other: Any?): Boolean {
return if (other is PseudoClassInternal) {
name == other.name && argsStr() == other.argsStr()
} else false
}
open fun argsStr(): String? = null
override fun toString(): String = ":$name${argsStr()?.let { "($it)" } ?: ""}"
// Linguistic pseudo-classes
internal class Lang internal constructor(val langCode: LanguageCode) : PseudoClassInternal("lang") {
override fun argsStr() = langCode
}
// Tree-structural pseudo-classes
internal class NthChild internal constructor(val nth: Nth) : PseudoClassInternal("nth-child") {
override fun argsStr() = "$nth"
}
internal class NthLastChild internal constructor(val nth: Nth) : PseudoClassInternal("nth-last-child") {
override fun argsStr() = "$nth"
}
internal class NthOfType internal constructor(val nth: Nth) : PseudoClassInternal("nth-of-type") {
override fun argsStr() = "$nth"
}
internal class NthLastOfType internal constructor(val nth: Nth) : PseudoClassInternal("nth-last-of-type") {
override fun argsStr() = "$nth"
}
internal class Host internal constructor(val selector: CSSSelector) : PseudoClassInternal("host") {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(selector), strict)
override fun argsStr() = "${selector.asString()}"
}
// Etc
internal class Not internal constructor(val selector: CSSSelector) : PseudoClassInternal("not") {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(selector), strict)
override fun argsStr() = "$selector"
}
} }
object PseudoElement { object PseudoElement {
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val after : CSSSelector = PseudoElementInternal("after") val after : CSSSelector = selectorScope.after
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val before : CSSSelector = PseudoElementInternal("before") val before : CSSSelector = selectorScope.before
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val cue : CSSSelector = PseudoElementInternal("cue") val cue : CSSSelector = selectorScope.cue
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val cueRegion : CSSSelector = PseudoElementInternal("cue-region") val cueRegion : CSSSelector = selectorScope.cueRegion
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val firstLetter : CSSSelector = PseudoElementInternal("first-letter") val firstLetter : CSSSelector = selectorScope.firstLetter
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val firstLine : CSSSelector = PseudoElementInternal("first-line") val firstLine : CSSSelector = selectorScope.firstLine
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val fileSelectorButton : CSSSelector = PseudoElementInternal("file-selector-button") val fileSelectorButton : CSSSelector = selectorScope.fileSelectorButton
@Deprecated(webCssSelectorsDeprecationMessage) @Deprecated(webCssSelectorsDeprecationMessage)
val selection : CSSSelector = PseudoElementInternal("selection") val selection : CSSSelector = selectorScope.selection
}
internal open class PseudoElementInternal internal constructor(val name: String) : CSSSelector() {
override fun equals(other: Any?): Boolean {
return if (other is PseudoElementInternal) {
name == other.name && argsStr() == other.argsStr()
} else false
}
open fun argsStr(): String? = null
override fun toString(): String = "::$name${argsStr()?.let { "($it)" } ?: ""}"
internal class Slotted internal constructor(val selector: CSSSelector) : PseudoElementInternal("slotted") {
override fun contains(other: CSSSelector, strict: Boolean): Boolean =
contains(this, other, listOf(selector), strict)
override fun argsStr() = selector.asString()
}
} }
} }
@Suppress("SuspiciousEqualsCombination")
private fun contains(that: CSSSelector, other: CSSSelector, children: List<CSSSelector>, strict: Boolean): Boolean {
return that === other || // exactly same selector
children.any { it.contains(other, strict) } || // contains it in children
(!strict && that == other) // equals structurally
}
internal const val webCssSelectorsDeprecationMessage = "Consider using a property from SelectorsScope"

Loading…
Cancel
Save