Validation changes, more properties, cleanup

This commit is contained in:
2020-02-26 19:55:10 +01:00
parent 083f234d82
commit b92b16f1b8
12 changed files with 200 additions and 89 deletions

View File

@@ -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")
}
}
}

View File

@@ -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()})"

View File

@@ -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")

View File

@@ -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}%")

View File

@@ -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")
}
}

View 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")
}
}

View File

@@ -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)

View File

@@ -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))
}
}

View File

@@ -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()

View 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'"
}

View File

@@ -0,0 +1,5 @@
package nl.astraeus.logging
import mu.KotlinLogging
val log = KotlinLogging.logger {}

View File

@@ -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))
}