feat: add expected type class feature in ValueRule for keyValuesRules

This commit is contained in:
2025-11-14 15:35:01 +08:00
parent a884be697c
commit d1626c7884
4 changed files with 92 additions and 14 deletions

View File

@@ -106,7 +106,9 @@ internal object DefaultDeployer {
val properties = mutableMapOf<String, PropertyTypeValue>()
val resolveProperties = mutableMapOf<Any?, Any?>()
config.permanentKeyValues.forEach { (key, value) -> properties[key] = value.createTypeValueByType(config.useTypeAutoConversion) }
config.permanentKeyValues.forEach { (key, value) ->
properties[key] = value.createTypeValueByType(config.useTypeAutoConversion, key)
}
config.locations.forEach { location ->
when (location) {
GropifyLocation.CurrentProject -> createProperties(config, descriptor.currentDir).forEach { resolveProperties.putAll(it) }
@@ -136,7 +138,7 @@ internal object DefaultDeployer {
}
} ?: true
}.toMutableMap().also { resolveKeyValues ->
resolveKeyValues.onEach { (key, value) ->
resolveKeyValues.forEach { (key, value) ->
val resolveKeys = mutableListOf<String>()
fun String.resolveValue(): String = replaceInterpolation { matchKey ->
@@ -155,17 +157,25 @@ internal object DefaultDeployer {
}
if (value.hasInterpolation()) resolveKeyValues[key] = value.resolveValue()
}.takeIf { config.keyValuesRules.isNotEmpty() }?.forEach { (key, value) ->
config.keyValuesRules[key]?.also { resolveKeyValues[key] = it(value) }
}
properties.putAll(resolveKeyValues.map { (key, value) ->
key to value.createTypeValue(config.useTypeAutoConversion)
key to value.createTypeValue(config.useTypeAutoConversion, key)
})
}
// Replace all key-values if exists.
config.replacementKeyValues.forEach { (key, value) -> properties[key] = value.createTypeValueByType(config.useTypeAutoConversion) }
config.replacementKeyValues.forEach { (key, value) ->
properties[key] = value.createTypeValueByType(config.useTypeAutoConversion, key)
}
// Apply key-values rules.
properties.forEach { (key, value) ->
val (mapper, type) = config.keyValuesRules[key] ?: return@forEach
val resolveValue = mapper(value.raw).createTypeValue(config.useTypeAutoConversion, key, type)
properties[key] = resolveValue
}
return properties
}

View File

@@ -30,11 +30,13 @@ import com.highcapable.gropify.plugin.Gropify
import com.highcapable.gropify.plugin.config.extension.create
import com.highcapable.gropify.plugin.config.proxy.GropifyConfig
import com.highcapable.gropify.plugin.config.type.GropifyLocation
import com.highcapable.gropify.plugin.generator.extension.PropertyValueMapper
import com.highcapable.gropify.plugin.generator.extension.PropertyValueRule
import com.highcapable.gropify.utils.KeywordsDetector
import com.highcapable.gropify.utils.extension.isStartsWithLetter
import org.gradle.api.Action
import org.gradle.api.initialization.Settings
import kotlin.reflect.KClass
/**
* Configure extension for Gropify.
@@ -447,8 +449,13 @@ open class GropifyConfigureExtension internal constructor() {
*
* ```kotlin
* keyValuesRules(
* "some.key1" to createValueRule { if (it.contains("_")) it.replace("_", "-") else it },
* "some.key2" to createValueRule { "$it-value" }
* "some.key1" to ValueRule { if (it.contains("_")) it.replace("_", "-") else it },
* "some.key2" to ValueRule { "$it-value" },
* // You can also specify the expected type class,
* // the type you specify will be used during generation,
* // and an exception will be thrown if the type cannot be converted correctly.
* // If the [useTypeAutoConversion] is not enabled, this parameter will be ignored.
* "some.key3" to ValueRule(Int::class)
* )
* ```
*
@@ -483,10 +490,13 @@ open class GropifyConfigureExtension internal constructor() {
/**
* Create a new properties' values rule.
* @param type specify the expected type class, or null to auto-detect,
* if the [useTypeAutoConversion] is not enabled, this parameter will be ignored.
* @param rule callback current rule.
* @return [PropertyValueRule]
*/
fun ValueRule(rule: PropertyValueRule) = rule
@JvmOverloads
fun ValueRule(type: KClass<*>? = null, rule: PropertyValueMapper = { it }) = rule to type
/**
* Set where to find properties' key-values.

View File

@@ -22,10 +22,12 @@
package com.highcapable.gropify.plugin.generator.extension
import com.highcapable.gropify.utils.extension.underscore
import kotlin.reflect.KClass
internal typealias PropertyMap = MutableMap<String, PropertyTypeValue>
internal typealias PropertyOptimizeMap = MutableMap<String, Pair<String, PropertyTypeValue>>
internal typealias PropertyValueRule = (value: String) -> String
internal typealias PropertyValueMapper = (value: String) -> String
internal typealias PropertyValueRule = Pair<PropertyValueMapper, KClass<*>?>
/**
* Optimize property keys for code generation.

View File

@@ -22,6 +22,7 @@
package com.highcapable.gropify.plugin.generator.extension
import com.highcapable.gropify.internal.error
import com.highcapable.gropify.internal.require
import com.highcapable.gropify.plugin.Gropify
import com.highcapable.gropify.utils.extension.isNumeric
import kotlin.reflect.KClass
@@ -30,9 +31,12 @@ import kotlin.reflect.KClass
* Create [PropertyTypeValue] from [String] value.
* @receiver [String]
* @param autoConversion whether to enable auto conversion.
* @param key the property key name.
* @param type specify the expected type class, or null to auto-detect,
* if the [autoConversion] is not `true`, this parameter will be ignored.
* @return [PropertyTypeValue]
*/
internal fun String.createTypeValue(autoConversion: Boolean): PropertyTypeValue {
internal fun String.createTypeValue(autoConversion: Boolean, key: String, type: KClass<*>? = null): PropertyTypeValue {
var isStringType = false
val valueString = replace("\n", "\\n")
.replace("\r", "\\r")
@@ -47,6 +51,56 @@ internal fun String.createTypeValue(autoConversion: Boolean): PropertyTypeValue
if (!autoConversion) return PropertyTypeValue(this, "\"$valueString\"", String::class)
val trimmed = valueString.trim()
if (type != null) {
val finalValue = when (type) {
String::class -> "\"$valueString\""
CharSequence::class -> "\"$valueString\""
Char::class -> trimmed.firstOrNull()?.let { "'$it'" }
?: Gropify.error("The \"$key\" value is empty and cannot be converted to Char type.")
Boolean::class -> if (trimmed.toBooleanStrictOrNull() != null)
trimmed
else ((trimmed.toIntOrNull() ?: 0) > 0).toString()
Int::class -> {
val intValue = trimmed.toIntOrNull()
Gropify.require(intValue != null && intValue in Int.MIN_VALUE..Int.MAX_VALUE) {
"The \"$key\" value \"$this\" cannot be converted to Int type."
}
trimmed
}
Long::class -> {
Gropify.require(trimmed.toLongOrNull() != null) {
"The \"$key\" value \"$this\" cannot be converted to Long type."
}
if (trimmed.endsWith("L")) trimmed else "${trimmed}L"
}
Double::class -> {
val doubleValue = trimmed.toDoubleOrNull()
Gropify.require(doubleValue != null && !doubleValue.isInfinite()) {
"The \"$key\" value \"$this\" cannot be converted to Double type."
}
trimmed
}
Float::class -> {
val floatValue = trimmed.toFloatOrNull()
Gropify.require(floatValue != null && !floatValue.isInfinite()) {
"The \"$key\" value \"$this\" cannot be converted to Float type."
}
if (trimmed.endsWith("f") || trimmed.endsWith("F")) trimmed else "${trimmed}f"
}
else -> Gropify.error(
"Unsupported property \"$key\" value type: ${type.qualifiedName}, " +
"only String, CharSequence, Char, Boolean, Int, Long, Float, Double are supported."
)
}
return PropertyTypeValue(this, finalValue, type)
}
val typeSpec = when {
isStringType -> String::class
trimmed.toBooleanStrictOrNull() != null -> Boolean::class
@@ -79,9 +133,10 @@ internal fun String.createTypeValue(autoConversion: Boolean): PropertyTypeValue
* Create [PropertyTypeValue] from [Any] value's type.
* @receiver [Any]
* @param autoConversion whether to enable auto conversion.
* @param key the property key name.
* @return [PropertyTypeValue]
*/
internal fun Any.createTypeValueByType(autoConversion: Boolean): PropertyTypeValue {
internal fun Any.createTypeValueByType(autoConversion: Boolean, key: String): PropertyTypeValue {
val typeSpec = this.javaClass.kotlin
val valueString = toString()
.replace("\n", "\\n")
@@ -94,12 +149,13 @@ internal fun Any.createTypeValueByType(autoConversion: Boolean): PropertyTypeVal
val finalValue = if (autoConversion) when (typeSpec) {
String::class, CharSequence::class -> "\"$trimmed\""
Char::class -> "'$trimmed'"
Boolean::class -> trimmed
Long::class -> if (trimmed.endsWith("L")) trimmed else "${trimmed}L"
Float::class -> if (trimmed.endsWith("f") || trimmed.endsWith("F")) trimmed else "${trimmed}f"
Int::class, Double::class -> trimmed
else -> Gropify.error(
"Unsupported property value type: ${typeSpec.qualifiedName}, " +
"only String, CharSequence, Char, Int, Long, Float, Double are supported."
"Unsupported property \"$key\" value type: ${typeSpec.qualifiedName}, " +
"only String, CharSequence, Char, Boolean, Int, Long, Float, Double are supported."
)
} else "\"$valueString\""