Validation changes, more properties, cleanup
This commit is contained in:
@@ -24,6 +24,8 @@ kotlin {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib-common"))
|
||||
|
||||
implementation("io.github.microutils:kotlin-logging-common:1.7.8")
|
||||
}
|
||||
}
|
||||
val commonTest by getting {
|
||||
@@ -35,6 +37,8 @@ kotlin {
|
||||
val jsMain by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib-js"))
|
||||
|
||||
implementation("io.github.microutils:kotlin-logging-js:1.7.8")
|
||||
}
|
||||
}
|
||||
val jsTest by getting {
|
||||
@@ -46,6 +50,10 @@ kotlin {
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib-jdk8"))
|
||||
|
||||
implementation("org.slf4j:slf4j-api:1.7.29")
|
||||
implementation("org.slf4j:slf4j-simple:1.7.29")
|
||||
implementation("io.github.microutils:kotlin-logging:1.7.8")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class CssBuilder {
|
||||
definition(this.definition)
|
||||
}
|
||||
|
||||
fun getCss(): String = definition.generateCss()
|
||||
fun getCss(minified: Boolean = false): String = definition.generateCss(minified = minified)
|
||||
|
||||
override fun toString(): String {
|
||||
return "CssBuilder(${definition.generateCss()})"
|
||||
|
||||
@@ -69,7 +69,7 @@ class AnimationTimingFunction(
|
||||
n2: Double,
|
||||
n3: Double,
|
||||
n4: Double
|
||||
) = AnimationTimingFunction("cubic-bezier($n1, $n2, $n3, $n4)")
|
||||
) = AnimationTimingFunction("cubic-bezier($n1,$n2,$n3,$n4)")
|
||||
fun initial() = AnimationTimingFunction("initial")
|
||||
fun inherit() = AnimationTimingFunction("inherit")
|
||||
|
||||
|
||||
@@ -31,50 +31,10 @@ class BackgroundBlendMode(
|
||||
}
|
||||
}
|
||||
|
||||
class BackgroundClip(
|
||||
value: String
|
||||
) : CssProperty(value) {
|
||||
|
||||
companion object {
|
||||
fun borderBox() = BackgroundClip("border-box")
|
||||
fun paddingBox() = BackgroundClip("padding-box")
|
||||
fun contentBox() = BackgroundClip("content-box")
|
||||
fun initial() = BackgroundClip("initial")
|
||||
fun inherit() = BackgroundClip("inherit")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class BackgroundOrigin(
|
||||
value: String
|
||||
) : CssProperty(value) {
|
||||
|
||||
companion object {
|
||||
fun borderBox() = BackgroundOrigin("border-box")
|
||||
fun paddingBox() = BackgroundOrigin("padding-box")
|
||||
fun contentBox() = BackgroundOrigin("content-box")
|
||||
fun initial() = BackgroundOrigin("initial")
|
||||
fun inherit() = BackgroundOrigin("inherit")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class BackgroundPosition(
|
||||
value: String
|
||||
) : CssProperty(value) {
|
||||
|
||||
override fun validateMultiple(props: List<*>) {
|
||||
for (prop in props) {
|
||||
if (prop is CssProperty) {
|
||||
if (prop.css() == "initial" || prop.css() == "inherit") {
|
||||
check(props.size == 1) {
|
||||
"'background-position' can only have single value when 'initial' or 'inherit'"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun left() = BackgroundPosition("left")
|
||||
fun center() = BackgroundPosition("center")
|
||||
@@ -106,12 +66,6 @@ class BackgroundSize(
|
||||
value: String
|
||||
) : CssProperty(value) {
|
||||
|
||||
override fun validateMultiple(props: List<*>) {
|
||||
check(props.size <= 2) {
|
||||
"'background-size' can not have more than 2 values"
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun px(px: Int) = BackgroundSize("${px}px")
|
||||
fun perc(pc: Double) = BackgroundSize("${pc}%")
|
||||
|
||||
@@ -4,21 +4,6 @@ class BorderRadius(
|
||||
value: String
|
||||
): CssProperty(value) {
|
||||
|
||||
override fun validateMultiple(props: List<*>) {
|
||||
check(props.size <= 2) {
|
||||
"'background-size' can not have more than 2 values"
|
||||
}
|
||||
for (prop in props) {
|
||||
if (prop is CssProperty) {
|
||||
if (prop.css() == "initial" || prop.css() == "inherit") {
|
||||
check(props.size == 1) {
|
||||
"'border-radius' can only have single value when 'initial' or 'inherit'"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun px(nr: Int) = BorderRadius("${nr}px")
|
||||
fun em(nr: Int) = BorderRadius("${nr}em")
|
||||
@@ -77,3 +62,13 @@ class BorderWidth(
|
||||
fun inherit() = BorderWidth("inherit")
|
||||
}
|
||||
}
|
||||
|
||||
class BorderCollapse(
|
||||
value: String
|
||||
): CssProperty(value) {
|
||||
|
||||
companion object {
|
||||
fun separate() = BorderWidth("separate")
|
||||
fun collapse() = BorderWidth("collapse")
|
||||
}
|
||||
}
|
||||
|
||||
36
src/commonMain/kotlin/nl/astraeus/css/properties/Common.kt
Normal file
36
src/commonMain/kotlin/nl/astraeus/css/properties/Common.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
package nl.astraeus.css.properties
|
||||
|
||||
class Length(
|
||||
value: String
|
||||
): CssProperty(value) {
|
||||
|
||||
companion object {
|
||||
fun px(nr: Int) = Length("${nr}px")
|
||||
fun em(nr: Int) = Length("${nr}em")
|
||||
fun em(nr: Double) = Length("${nr}em")
|
||||
fun perc(nr: Int) = Length("${nr}%")
|
||||
fun perc(nr: Double) = Length("${nr}%")
|
||||
fun pc(nr: Int) = Length("${nr}pc")
|
||||
fun pc(nr: Double) = Length("${nr}pc")
|
||||
fun cm(nr: Int) = Length("${nr}cm")
|
||||
fun cm(nr: Double) = Length("${nr}cm")
|
||||
fun initial() = Length("initial")
|
||||
fun inherit() = Length("inherit")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ClipOrigin(
|
||||
value: String
|
||||
) : CssProperty(value) {
|
||||
|
||||
companion object {
|
||||
fun borderBox() = ClipOrigin("border-box")
|
||||
fun paddingBox() = ClipOrigin("padding-box")
|
||||
fun contentBox() = ClipOrigin("content-box")
|
||||
fun initial() = ClipOrigin("initial")
|
||||
fun inherit() = ClipOrigin("inherit")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,9 @@ package nl.astraeus.css.properties
|
||||
open class CssProperty(
|
||||
val value: String
|
||||
) {
|
||||
|
||||
fun css(): String = value
|
||||
|
||||
open fun validate() {}
|
||||
|
||||
open fun validateMultiple(props: List<*>) {}
|
||||
}
|
||||
|
||||
fun text(value: String) = TextProperty(value)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package nl.astraeus.css.style
|
||||
|
||||
import nl.astraeus.css.properties.*
|
||||
import nl.astraeus.logging.log
|
||||
|
||||
@DslMarker
|
||||
annotation class CssTagMarker
|
||||
@@ -25,21 +26,24 @@ open class Style(
|
||||
var background: TextProperty? = null,
|
||||
var backgroundAttachment: BackgroundAttachment? = null,
|
||||
var backgroundBlendMode: BackgroundBlendMode? = null,
|
||||
var backgroundClip: BackgroundClip? = null,
|
||||
var backgroundClip: ClipOrigin? = null,
|
||||
var backgroundColor: Color? = null,
|
||||
var backgroundImage: Image? = null,
|
||||
var backgroundOrigin: BackgroundOrigin? = null,
|
||||
var backgroundOrigin: ClipOrigin? = null,
|
||||
var backgroundPosition: List<BackgroundPosition>? = null,
|
||||
var backgroundRepeat: List<BackgroundRepeat>? = null,
|
||||
var backgroundSize: List<BackgroundSize>? = null,
|
||||
var border: TextProperty? = null,
|
||||
var borderBottom: TextProperty? = null,
|
||||
var borderColor: Color? = null,
|
||||
var borderBottomColor: Color? = null,
|
||||
var borderBottomLeftRadius: List<BorderRadius>? = null,
|
||||
var borderBottomRightRadius: List<BorderRadius>? = null,
|
||||
var borderBottomStyle: BorderStyle? = null,
|
||||
var borderBottomWidth: BorderWidth? = null,
|
||||
var borderCollapse: BorderCollapse? = null,
|
||||
var borderColor: List<Color>? = null,
|
||||
var borderImage: TextProperty? = null,
|
||||
var borderImageOutset: Length? = null,
|
||||
var borderLeft: TextProperty? = null,
|
||||
var borderLeftColor: Color? = null,
|
||||
var borderRadius: List<BorderRadius>? = null,
|
||||
@@ -57,8 +61,17 @@ open class Style(
|
||||
var transitionDuration: DelayDuration? = null,
|
||||
var width: Measurement? = null
|
||||
) {
|
||||
private val validators = mapOf<String, List<Validator>>(
|
||||
"background-position" to listOf(InitialInheritSingleValue()),
|
||||
"background-size" to listOf(MaxCountValidator(2)),
|
||||
"border-radius" to listOf(
|
||||
MaxCountValidator(4),
|
||||
InitialInheritSingleValue()
|
||||
),
|
||||
"animation-timing-function" to listOf(MaxCountValidator(4))
|
||||
)
|
||||
|
||||
fun getMapping() = mapOf(
|
||||
fun getMapping(): Map<String, Any?> = mapOf(
|
||||
"align-content" to alignContent,
|
||||
"align-items" to alignItems,
|
||||
"align-self" to alignSelf,
|
||||
@@ -89,9 +102,15 @@ open class Style(
|
||||
"border-bottom-color" to borderBottomColor,
|
||||
"border-bottom-left-radius" to borderBottomLeftRadius,
|
||||
"border-bottom-right-radius" to borderBottomRightRadius,
|
||||
"border-bottom-style" to borderBottomStyle,
|
||||
"border-bottom-width" to borderBottomWidth,
|
||||
"border-collapse" to borderCollapse,
|
||||
"border-color" to borderColor,
|
||||
"border-image" to borderImage,
|
||||
"border-image-outset" to borderImageOutset,
|
||||
"border-left" to borderLeft,
|
||||
"border-left-color" to borderLeftColor,
|
||||
"border-radius" to borderRadius,
|
||||
"border-right" to borderRight,
|
||||
"border-right-color" to borderRightColor,
|
||||
"border-top" to borderTop,
|
||||
@@ -107,38 +126,75 @@ open class Style(
|
||||
"width" to width
|
||||
)
|
||||
|
||||
fun propertyCss(indent: String, name: String, prop: CssProperty): String {
|
||||
prop.validate()
|
||||
fun propertyCss(indent: String, name: String, prop: CssProperty, minified: Boolean): String {
|
||||
validators[name]?.forEach {
|
||||
if (!it.validate(prop)) {
|
||||
log.warn { "Validate error '$name' - ${it.getMessage(name)}" }
|
||||
}
|
||||
}
|
||||
|
||||
return "$indent$name: ${prop.css()};\n"
|
||||
return if (!minified) {
|
||||
val paddedName = StringBuilder()
|
||||
paddedName.append(indent)
|
||||
paddedName.append(name)
|
||||
paddedName.append(":")
|
||||
while(paddedName.length < 32) {
|
||||
paddedName.append(' ')
|
||||
}
|
||||
"$paddedName${prop.css()};\n"
|
||||
} else {
|
||||
"$name:${prop.css()};"
|
||||
}
|
||||
}
|
||||
|
||||
fun propertyCss(indent: String, name: String, props: List<*>): String {
|
||||
fun propertyCss(indent: String, name: String, props: List<*>, minified: Boolean): String {
|
||||
val builder = StringBuilder()
|
||||
|
||||
validators[name]?.forEach {
|
||||
if (!it.validate(props as List<CssProperty>)) {
|
||||
log.warn { "Validate error '$name' - ${it.getListMessage(name)}" }
|
||||
}
|
||||
}
|
||||
|
||||
for ((index, prop) in props.withIndex()) {
|
||||
if (prop is CssProperty) {
|
||||
if (index == 0) {
|
||||
prop.validateMultiple(props)
|
||||
validators[name]?.forEach {
|
||||
if (!it.validate(prop)) {
|
||||
log.warn { "Validate error '$name' - ${it.getMessage(name)}" }
|
||||
}
|
||||
}
|
||||
if (builder.isNotEmpty()) {
|
||||
builder.append(", ")
|
||||
builder.append(",")
|
||||
if (!minified) {
|
||||
builder.append(" ")
|
||||
}
|
||||
}
|
||||
builder.append(prop.css())
|
||||
}
|
||||
}
|
||||
|
||||
return "$indent$name: $builder;\n"
|
||||
return if (!minified) {
|
||||
val paddedName = StringBuilder()
|
||||
paddedName.append(indent)
|
||||
paddedName.append(name)
|
||||
paddedName.append(":")
|
||||
while(paddedName.length < 32) {
|
||||
paddedName.append(' ')
|
||||
}
|
||||
"$paddedName$builder;\n"
|
||||
} else {
|
||||
"$name:$builder;"
|
||||
}
|
||||
}
|
||||
|
||||
fun generatePropertyCss(indent: String): String {
|
||||
fun generatePropertyCss(indent: String, minified: Boolean): String {
|
||||
val builder = StringBuilder()
|
||||
|
||||
for ((name, prop) in getMapping()) {
|
||||
if (prop is List<*> && prop.isNotEmpty()) {
|
||||
builder.append(propertyCss(indent, name, prop))
|
||||
builder.append(propertyCss(indent, name, prop, minified))
|
||||
} else if (prop is CssProperty) {
|
||||
builder.append(propertyCss(indent, name, prop))
|
||||
builder.append(propertyCss(indent, name, prop, minified))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,23 +17,32 @@ open class StyleDefinition : Style() {
|
||||
includes.add(style)
|
||||
}
|
||||
|
||||
open fun generateCss(namespace: String = "", indent: String = " "): String {
|
||||
open fun generateCss(namespace: String = "", indent: String = " ", minified: Boolean = false): String {
|
||||
val builder = StringBuilder()
|
||||
|
||||
for ((name, prop) in definitions) {
|
||||
val css = StringBuilder()
|
||||
css.append(prop.generatePropertyCss(indent))
|
||||
css.append(prop.generatePropertyCss(indent, minified))
|
||||
for (style in prop.includes) {
|
||||
css.append(style.generatePropertyCss(indent))
|
||||
css.append(style.generatePropertyCss(indent, minified))
|
||||
}
|
||||
if (css.isNotBlank()) {
|
||||
builder.append("$namespace $name".trim())
|
||||
builder.append(" {\n")
|
||||
builder.append("\n$namespace $name".trim())
|
||||
if (!minified) {
|
||||
builder.append(" ")
|
||||
}
|
||||
builder.append("{")
|
||||
if (!minified) {
|
||||
builder.append("\n")
|
||||
}
|
||||
builder.append(css)
|
||||
builder.append("}\n\n")
|
||||
builder.append("}")
|
||||
if (!minified) {
|
||||
builder.append("\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
builder.append(prop.generateCss( "${namespace} $name".trim(), indent))
|
||||
builder.append(prop.generateCss( "$namespace $name".trim(), indent, minified))
|
||||
}
|
||||
|
||||
return builder.toString()
|
||||
|
||||
41
src/commonMain/kotlin/nl/astraeus/css/style/Validator.kt
Normal file
41
src/commonMain/kotlin/nl/astraeus/css/style/Validator.kt
Normal file
@@ -0,0 +1,41 @@
|
||||
package nl.astraeus.css.style
|
||||
|
||||
import nl.astraeus.css.properties.CssProperty
|
||||
|
||||
abstract class Validator {
|
||||
|
||||
open fun validate(property: CssProperty): Boolean = true
|
||||
|
||||
open fun validate(properties: List<CssProperty>): Boolean = true
|
||||
|
||||
open fun getMessage(name: String): String = "'$name' validation message not defined for $this"
|
||||
|
||||
open fun getListMessage(name: String): String = "'$name' validation message not defined for $this"
|
||||
|
||||
}
|
||||
|
||||
class MaxCountValidator(
|
||||
val number: Int
|
||||
): Validator() {
|
||||
|
||||
override fun validate(property: List<CssProperty>): Boolean = property.size <= number
|
||||
|
||||
override fun getListMessage(name: String): String = "'$name' should not have more than 4 entries"
|
||||
|
||||
}
|
||||
|
||||
class InitialInheritSingleValue: Validator() {
|
||||
|
||||
override fun validate(properties: List<CssProperty>): Boolean {
|
||||
for (prop in properties) {
|
||||
if (prop.css() == "initial" || prop.css() == "inherit") {
|
||||
return properties.size == 1
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getListMessage(name: String): String = "'$name' can only have single value when 'initial' or 'inherit'"
|
||||
|
||||
}
|
||||
5
src/commonMain/kotlin/nl/astraeus/logging/Logger.kt
Normal file
5
src/commonMain/kotlin/nl/astraeus/logging/Logger.kt
Normal file
@@ -0,0 +1,5 @@
|
||||
package nl.astraeus.logging
|
||||
|
||||
import mu.KotlinLogging
|
||||
|
||||
val log = KotlinLogging.logger {}
|
||||
@@ -54,7 +54,7 @@ private fun generateCss(
|
||||
|
||||
css("a") {
|
||||
width = Measurement.px(725)
|
||||
background = text("")
|
||||
background = text("red initial")
|
||||
backgroundColor = base.mainBackgroundColor
|
||||
all = All.initial()
|
||||
}
|
||||
@@ -89,10 +89,19 @@ fun main() {
|
||||
animationIterationCount = listOf(
|
||||
Count.count(3), Count.infinite())
|
||||
animationTimingFunction = listOf(AnimationTimingFunction.cubicBezier(0.1, 0.2, 0.3, 0.4), AnimationTimingFunction.easeInOut())
|
||||
borderRadius = listOf(
|
||||
BorderRadius.px(4),
|
||||
BorderRadius.px(5),
|
||||
BorderRadius.px(6),
|
||||
BorderRadius.px(7),
|
||||
BorderRadius.px(8)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println("======")
|
||||
println(sd.generateCss())
|
||||
println("======")
|
||||
println(sd.generateCss(minified = true))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user