mirror of
https://github.com/HighCapable/Gropify.git
synced 2025-12-11 15:53:54 +08:00
feat: add expected type class feature in ValueRule for keyValuesRules
This commit is contained in:
@@ -106,7 +106,9 @@ internal object DefaultDeployer {
|
|||||||
val properties = mutableMapOf<String, PropertyTypeValue>()
|
val properties = mutableMapOf<String, PropertyTypeValue>()
|
||||||
val resolveProperties = mutableMapOf<Any?, Any?>()
|
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 ->
|
config.locations.forEach { location ->
|
||||||
when (location) {
|
when (location) {
|
||||||
GropifyLocation.CurrentProject -> createProperties(config, descriptor.currentDir).forEach { resolveProperties.putAll(it) }
|
GropifyLocation.CurrentProject -> createProperties(config, descriptor.currentDir).forEach { resolveProperties.putAll(it) }
|
||||||
@@ -136,7 +138,7 @@ internal object DefaultDeployer {
|
|||||||
}
|
}
|
||||||
} ?: true
|
} ?: true
|
||||||
}.toMutableMap().also { resolveKeyValues ->
|
}.toMutableMap().also { resolveKeyValues ->
|
||||||
resolveKeyValues.onEach { (key, value) ->
|
resolveKeyValues.forEach { (key, value) ->
|
||||||
val resolveKeys = mutableListOf<String>()
|
val resolveKeys = mutableListOf<String>()
|
||||||
|
|
||||||
fun String.resolveValue(): String = replaceInterpolation { matchKey ->
|
fun String.resolveValue(): String = replaceInterpolation { matchKey ->
|
||||||
@@ -155,17 +157,25 @@ internal object DefaultDeployer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (value.hasInterpolation()) resolveKeyValues[key] = value.resolveValue()
|
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) ->
|
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.
|
// 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
|
return properties
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,13 @@ import com.highcapable.gropify.plugin.Gropify
|
|||||||
import com.highcapable.gropify.plugin.config.extension.create
|
import com.highcapable.gropify.plugin.config.extension.create
|
||||||
import com.highcapable.gropify.plugin.config.proxy.GropifyConfig
|
import com.highcapable.gropify.plugin.config.proxy.GropifyConfig
|
||||||
import com.highcapable.gropify.plugin.config.type.GropifyLocation
|
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.plugin.generator.extension.PropertyValueRule
|
||||||
import com.highcapable.gropify.utils.KeywordsDetector
|
import com.highcapable.gropify.utils.KeywordsDetector
|
||||||
import com.highcapable.gropify.utils.extension.isStartsWithLetter
|
import com.highcapable.gropify.utils.extension.isStartsWithLetter
|
||||||
import org.gradle.api.Action
|
import org.gradle.api.Action
|
||||||
import org.gradle.api.initialization.Settings
|
import org.gradle.api.initialization.Settings
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure extension for Gropify.
|
* Configure extension for Gropify.
|
||||||
@@ -447,8 +449,13 @@ open class GropifyConfigureExtension internal constructor() {
|
|||||||
*
|
*
|
||||||
* ```kotlin
|
* ```kotlin
|
||||||
* keyValuesRules(
|
* keyValuesRules(
|
||||||
* "some.key1" to createValueRule { if (it.contains("_")) it.replace("_", "-") else it },
|
* "some.key1" to ValueRule { if (it.contains("_")) it.replace("_", "-") else it },
|
||||||
* "some.key2" to createValueRule { "$it-value" }
|
* "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.
|
* 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.
|
* @param rule callback current rule.
|
||||||
* @return [PropertyValueRule]
|
* @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.
|
* Set where to find properties' key-values.
|
||||||
|
|||||||
@@ -22,10 +22,12 @@
|
|||||||
package com.highcapable.gropify.plugin.generator.extension
|
package com.highcapable.gropify.plugin.generator.extension
|
||||||
|
|
||||||
import com.highcapable.gropify.utils.extension.underscore
|
import com.highcapable.gropify.utils.extension.underscore
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
internal typealias PropertyMap = MutableMap<String, PropertyTypeValue>
|
internal typealias PropertyMap = MutableMap<String, PropertyTypeValue>
|
||||||
internal typealias PropertyOptimizeMap = MutableMap<String, Pair<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.
|
* Optimize property keys for code generation.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
package com.highcapable.gropify.plugin.generator.extension
|
package com.highcapable.gropify.plugin.generator.extension
|
||||||
|
|
||||||
import com.highcapable.gropify.internal.error
|
import com.highcapable.gropify.internal.error
|
||||||
|
import com.highcapable.gropify.internal.require
|
||||||
import com.highcapable.gropify.plugin.Gropify
|
import com.highcapable.gropify.plugin.Gropify
|
||||||
import com.highcapable.gropify.utils.extension.isNumeric
|
import com.highcapable.gropify.utils.extension.isNumeric
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@@ -30,9 +31,12 @@ import kotlin.reflect.KClass
|
|||||||
* Create [PropertyTypeValue] from [String] value.
|
* Create [PropertyTypeValue] from [String] value.
|
||||||
* @receiver [String]
|
* @receiver [String]
|
||||||
* @param autoConversion whether to enable auto conversion.
|
* @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]
|
* @return [PropertyTypeValue]
|
||||||
*/
|
*/
|
||||||
internal fun String.createTypeValue(autoConversion: Boolean): PropertyTypeValue {
|
internal fun String.createTypeValue(autoConversion: Boolean, key: String, type: KClass<*>? = null): PropertyTypeValue {
|
||||||
var isStringType = false
|
var isStringType = false
|
||||||
val valueString = replace("\n", "\\n")
|
val valueString = replace("\n", "\\n")
|
||||||
.replace("\r", "\\r")
|
.replace("\r", "\\r")
|
||||||
@@ -47,6 +51,56 @@ internal fun String.createTypeValue(autoConversion: Boolean): PropertyTypeValue
|
|||||||
if (!autoConversion) return PropertyTypeValue(this, "\"$valueString\"", String::class)
|
if (!autoConversion) return PropertyTypeValue(this, "\"$valueString\"", String::class)
|
||||||
|
|
||||||
val trimmed = valueString.trim()
|
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 {
|
val typeSpec = when {
|
||||||
isStringType -> String::class
|
isStringType -> String::class
|
||||||
trimmed.toBooleanStrictOrNull() != null -> Boolean::class
|
trimmed.toBooleanStrictOrNull() != null -> Boolean::class
|
||||||
@@ -79,9 +133,10 @@ internal fun String.createTypeValue(autoConversion: Boolean): PropertyTypeValue
|
|||||||
* Create [PropertyTypeValue] from [Any] value's type.
|
* Create [PropertyTypeValue] from [Any] value's type.
|
||||||
* @receiver [Any]
|
* @receiver [Any]
|
||||||
* @param autoConversion whether to enable auto conversion.
|
* @param autoConversion whether to enable auto conversion.
|
||||||
|
* @param key the property key name.
|
||||||
* @return [PropertyTypeValue]
|
* @return [PropertyTypeValue]
|
||||||
*/
|
*/
|
||||||
internal fun Any.createTypeValueByType(autoConversion: Boolean): PropertyTypeValue {
|
internal fun Any.createTypeValueByType(autoConversion: Boolean, key: String): PropertyTypeValue {
|
||||||
val typeSpec = this.javaClass.kotlin
|
val typeSpec = this.javaClass.kotlin
|
||||||
val valueString = toString()
|
val valueString = toString()
|
||||||
.replace("\n", "\\n")
|
.replace("\n", "\\n")
|
||||||
@@ -94,12 +149,13 @@ internal fun Any.createTypeValueByType(autoConversion: Boolean): PropertyTypeVal
|
|||||||
val finalValue = if (autoConversion) when (typeSpec) {
|
val finalValue = if (autoConversion) when (typeSpec) {
|
||||||
String::class, CharSequence::class -> "\"$trimmed\""
|
String::class, CharSequence::class -> "\"$trimmed\""
|
||||||
Char::class -> "'$trimmed'"
|
Char::class -> "'$trimmed'"
|
||||||
|
Boolean::class -> trimmed
|
||||||
Long::class -> if (trimmed.endsWith("L")) trimmed else "${trimmed}L"
|
Long::class -> if (trimmed.endsWith("L")) trimmed else "${trimmed}L"
|
||||||
Float::class -> if (trimmed.endsWith("f") || trimmed.endsWith("F")) trimmed else "${trimmed}f"
|
Float::class -> if (trimmed.endsWith("f") || trimmed.endsWith("F")) trimmed else "${trimmed}f"
|
||||||
Int::class, Double::class -> trimmed
|
Int::class, Double::class -> trimmed
|
||||||
else -> Gropify.error(
|
else -> Gropify.error(
|
||||||
"Unsupported property value type: ${typeSpec.qualifiedName}, " +
|
"Unsupported property \"$key\" value type: ${typeSpec.qualifiedName}, " +
|
||||||
"only String, CharSequence, Char, Int, Long, Float, Double are supported."
|
"only String, CharSequence, Char, Boolean, Int, Long, Float, Double are supported."
|
||||||
)
|
)
|
||||||
} else "\"$valueString\""
|
} else "\"$valueString\""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user