mirror of
https://github.com/HighCapable/Gropify.git
synced 2025-12-10 15:24:07 +08:00
refactor: replace Any type with PropertyTypeValue in generator and deployer classes
This commit is contained in:
@@ -28,6 +28,9 @@ import com.highcapable.gropify.plugin.config.type.GropifyLocation
|
||||
import com.highcapable.gropify.plugin.deployer.BuildscriptDeployer
|
||||
import com.highcapable.gropify.plugin.deployer.SourceCodeDeployer
|
||||
import com.highcapable.gropify.plugin.generator.extension.PropertyMap
|
||||
import com.highcapable.gropify.plugin.generator.extension.PropertyTypeValue
|
||||
import com.highcapable.gropify.plugin.generator.extension.createTypeValue
|
||||
import com.highcapable.gropify.plugin.generator.extension.createTypeValueByType
|
||||
import com.highcapable.gropify.utils.extension.hasInterpolation
|
||||
import com.highcapable.gropify.utils.extension.removeSurroundingQuotes
|
||||
import com.highcapable.gropify.utils.extension.replaceInterpolation
|
||||
@@ -100,10 +103,10 @@ internal object DefaultDeployer {
|
||||
* @return [PropertyMap]
|
||||
*/
|
||||
fun generateMap(config: GropifyConfig.CommonGenerateConfig, descriptor: ProjectDescriptor): PropertyMap {
|
||||
val properties = mutableMapOf<String, Any>()
|
||||
val properties = mutableMapOf<String, PropertyTypeValue>()
|
||||
val resolveProperties = mutableMapOf<Any?, Any?>()
|
||||
|
||||
config.permanentKeyValues.forEach { (key, value) -> properties[key] = value }
|
||||
config.permanentKeyValues.forEach { (key, value) -> properties[key] = value.createTypeValueByType(config.useTypeAutoConversion) }
|
||||
config.locations.forEach { location ->
|
||||
when (location) {
|
||||
GropifyLocation.CurrentProject -> createProperties(config, descriptor.currentDir).forEach { resolveProperties.putAll(it) }
|
||||
@@ -156,11 +159,13 @@ internal object DefaultDeployer {
|
||||
config.keyValuesRules[key]?.also { resolveKeyValues[key] = it(value) }
|
||||
}
|
||||
|
||||
properties.putAll(resolveKeyValues)
|
||||
properties.putAll(resolveKeyValues.map { (key, value) ->
|
||||
key to value.createTypeValue(config.useTypeAutoConversion)
|
||||
})
|
||||
}
|
||||
|
||||
// Replace all key-values if exists.
|
||||
config.replacementKeyValues.forEach { (key, value) -> properties[key] = value }
|
||||
config.replacementKeyValues.forEach { (key, value) -> properties[key] = value.createTypeValueByType(config.useTypeAutoConversion) }
|
||||
|
||||
return properties
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.highcapable.gropify.plugin.Gropify
|
||||
import com.highcapable.gropify.plugin.config.proxy.GropifyConfig
|
||||
import com.highcapable.gropify.plugin.extension.accessors.proxy.ExtensionAccessors
|
||||
import com.highcapable.gropify.plugin.generator.extension.PropertyMap
|
||||
import com.highcapable.gropify.plugin.generator.extension.createTypedValue
|
||||
import com.highcapable.gropify.plugin.generator.extension.PropertyTypeValue
|
||||
import com.highcapable.gropify.plugin.generator.extension.toOptimize
|
||||
import com.highcapable.gropify.plugin.generator.extension.toPoetNoEscape
|
||||
import com.highcapable.gropify.utils.extension.capitalize
|
||||
@@ -43,7 +43,6 @@ import com.palantir.javapoet.JavaFile
|
||||
import com.palantir.javapoet.MethodSpec
|
||||
import com.palantir.javapoet.TypeSpec
|
||||
import javax.lang.model.element.Modifier
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
* Generator for buildscript accessors classes.
|
||||
@@ -70,8 +69,6 @@ internal class BuildscriptGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
private var config by Delegates.notNull<GropifyConfig.BuildscriptGenerateConfig>()
|
||||
|
||||
private val classSpecs = mutableMapOf<String, TypeSpec.Builder>()
|
||||
private val constructorSpecs = mutableMapOf<String, MethodSpec.Builder>()
|
||||
private val preAddConstructorSpecNames = mutableListOf<Pair<String, String>>()
|
||||
@@ -135,16 +132,15 @@ internal class BuildscriptGenerator {
|
||||
}.build()
|
||||
)
|
||||
|
||||
private fun TypeSpec.Builder.addFinalValueMethod(accessorsName: String, methodName: String, className: String, value: Any) =
|
||||
private fun TypeSpec.Builder.addFinalValueMethod(accessorsName: String, methodName: String, className: String, value: PropertyTypeValue) =
|
||||
addMethod(
|
||||
MethodSpec.methodBuilder("get${getOrCreateUsedSuccessiveMethodName(methodName, className).capitalize()}").apply {
|
||||
val typedValue = value.createTypedValue(config.useTypeAutoConversion)
|
||||
val safeValueForJavadoc = typedValue.second.replace("$", "$$")
|
||||
val safeValueForJavadoc = value.codeValue.replace("$", "$$")
|
||||
|
||||
addJavadoc("Resolve the \"$accessorsName\" value \"${value.toString().toPoetNoEscape()}\".")
|
||||
addJavadoc("Resolve the \"$accessorsName\" value \"${value.raw.toPoetNoEscape()}\".")
|
||||
|
||||
addModifiers(Modifier.PUBLIC, Modifier.FINAL)
|
||||
returns(typedValue.first.java)
|
||||
returns(value.type.java)
|
||||
addStatement("return $safeValueForJavadoc")
|
||||
}.build()
|
||||
)
|
||||
@@ -176,7 +172,7 @@ internal class BuildscriptGenerator {
|
||||
*
|
||||
* After the parsing is completed, we need to call [releaseParseTypeSpec] to complete the parsing.
|
||||
*/
|
||||
private fun parseTypeSpec(successiveName: String, key: String, value: Any) {
|
||||
private fun parseTypeSpec(successiveName: String, key: String, value: PropertyTypeValue) {
|
||||
fun String.duplicateGrandSuccessiveIndex() = lowercase().let { name ->
|
||||
if (grandSuccessiveDuplicateIndexes.contains(name)) {
|
||||
grandSuccessiveDuplicateIndexes[name] = (grandSuccessiveDuplicateIndexes[name] ?: 1) + 1
|
||||
@@ -274,8 +270,6 @@ internal class BuildscriptGenerator {
|
||||
"Class name cannot be empty or blank."
|
||||
}
|
||||
|
||||
this.config = config
|
||||
|
||||
val topClassName = "${config.name.replace(":", "_").upperCamelcase()}$TOP_CLASS_SUFFIX_NAME"
|
||||
|
||||
memoryExtensionClasses[config.name] = "$ACCESSORS_PACKAGE_NAME.$topClassName"
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.highcapable.gropify.plugin.config.proxy.GropifyConfig
|
||||
import com.highcapable.gropify.plugin.generator.config.GenerateConfig
|
||||
import com.highcapable.gropify.plugin.generator.config.SourceCodeSpec
|
||||
import com.highcapable.gropify.plugin.generator.extension.PropertyMap
|
||||
import com.highcapable.gropify.plugin.generator.extension.createTypedValue
|
||||
import com.highcapable.gropify.plugin.generator.extension.toOptimize
|
||||
import com.highcapable.gropify.plugin.generator.extension.toPoetNoEscape
|
||||
import com.highcapable.gropify.plugin.generator.extension.toPoetSpace
|
||||
@@ -62,17 +61,18 @@ internal class JavaCodeGenerator {
|
||||
|
||||
if (!config.isRestrictedAccessEnabled) addModifiers(Modifier.PUBLIC)
|
||||
keyValues.toOptimize().toUnderscores().forEach { (key, value) ->
|
||||
val typedValue = value.second.createTypedValue(config.useTypeAutoConversion)
|
||||
val currentKey = value.first
|
||||
val currentValue = value.second
|
||||
|
||||
addField(
|
||||
FieldSpec.builder(typedValue.first.java, key.firstNumberToLetter()).apply {
|
||||
addJavadoc("Resolve the \"${value.first.toPoetNoEscape()}\" value \"${value.second.toString().toPoetNoEscape()}\".")
|
||||
FieldSpec.builder(currentValue.type.java, key.firstNumberToLetter()).apply {
|
||||
addJavadoc("Resolve the \"${currentKey.toPoetNoEscape()}\" value \"${currentValue.raw.toPoetNoEscape()}\".")
|
||||
|
||||
if (!config.isRestrictedAccessEnabled)
|
||||
addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
|
||||
else addModifiers(Modifier.STATIC, Modifier.FINAL)
|
||||
|
||||
initializer(typedValue.second.toPoetNoEscape().toPoetSpace())
|
||||
initializer(currentValue.codeValue.toPoetNoEscape().toPoetSpace())
|
||||
}.build()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.highcapable.gropify.plugin.config.proxy.GropifyConfig
|
||||
import com.highcapable.gropify.plugin.generator.config.GenerateConfig
|
||||
import com.highcapable.gropify.plugin.generator.config.SourceCodeSpec
|
||||
import com.highcapable.gropify.plugin.generator.extension.PropertyMap
|
||||
import com.highcapable.gropify.plugin.generator.extension.createTypedValue
|
||||
import com.highcapable.gropify.plugin.generator.extension.toOptimize
|
||||
import com.highcapable.gropify.plugin.generator.extension.toPoetNoEscape
|
||||
import com.highcapable.gropify.plugin.generator.extension.toPoetSpace
|
||||
@@ -66,14 +65,15 @@ internal class KotlinCodeGenerator {
|
||||
|
||||
if (config.isRestrictedAccessEnabled) addModifiers(KModifier.INTERNAL)
|
||||
keyValues.toOptimize().toUnderscores().forEach { (key, value) ->
|
||||
val typedValue = value.second.createTypedValue(config.useTypeAutoConversion)
|
||||
val currentKey = value.first
|
||||
val currentValue = value.second
|
||||
|
||||
addProperty(PropertySpec.builder(key.firstNumberToLetter(), typedValue.first).apply {
|
||||
addKdoc("Resolve the \"${value.first.toPoetNoEscape()}\" value \"${value.second.toString().toPoetNoEscape()}\".")
|
||||
addProperty(PropertySpec.builder(key.firstNumberToLetter(), currentValue.type).apply {
|
||||
addKdoc("Resolve the \"${currentKey.toPoetNoEscape()}\" value \"${currentValue.raw.toPoetNoEscape()}\".")
|
||||
|
||||
if (config.isRestrictedAccessEnabled) addModifiers(KModifier.INTERNAL)
|
||||
addModifiers(KModifier.CONST)
|
||||
initializer(typedValue.second.toPoetNoEscape().toPoetSpace())
|
||||
initializer(currentValue.codeValue.toPoetNoEscape().toPoetSpace())
|
||||
}.build())
|
||||
}
|
||||
}.build())
|
||||
|
||||
@@ -21,63 +21,12 @@
|
||||
*/
|
||||
package com.highcapable.gropify.plugin.generator.extension
|
||||
|
||||
import com.highcapable.gropify.utils.extension.isNumeric
|
||||
import com.highcapable.gropify.utils.extension.underscore
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal typealias PropertyMap = MutableMap<String, Any>
|
||||
internal typealias PropertyOptimizeMap = MutableMap<String, Pair<String, Any>>
|
||||
internal typealias PropertyMap = MutableMap<String, PropertyTypeValue>
|
||||
internal typealias PropertyOptimizeMap = MutableMap<String, Pair<String, PropertyTypeValue>>
|
||||
internal typealias PropertyValueRule = (value: String) -> String
|
||||
|
||||
/**
|
||||
* Create typed value from [Any] value.
|
||||
* @param autoConversion whether to enable auto conversion.
|
||||
* @return [Pair]<[KClass], [String]>
|
||||
*/
|
||||
internal fun Any.createTypedValue(autoConversion: Boolean): Pair<KClass<*>, String> {
|
||||
var isStringType = false
|
||||
val valueString = toString()
|
||||
.replace("\n", "\\n")
|
||||
.replace("\r", "\\r")
|
||||
.replace("\\", "\\\\")
|
||||
.let {
|
||||
if (autoConversion && (it.startsWith("\"") && it.endsWith("\"") || it.startsWith("'") && it.endsWith("'"))) {
|
||||
isStringType = true
|
||||
it.drop(1).dropLast(1)
|
||||
} else it.replace("\"", "\\\"")
|
||||
}
|
||||
|
||||
if (!autoConversion) return String::class to "\"$valueString\""
|
||||
|
||||
val trimmed = valueString.trim()
|
||||
val typeSpec = when {
|
||||
isStringType -> String::class
|
||||
trimmed.toBooleanStrictOrNull() != null -> Boolean::class
|
||||
trimmed.isNumeric() ->
|
||||
if (!trimmed.contains(".")) {
|
||||
val longValue = trimmed.toLongOrNull()
|
||||
when (longValue) {
|
||||
null -> String::class
|
||||
in Int.MIN_VALUE..Int.MAX_VALUE -> Int::class
|
||||
else -> Long::class
|
||||
}
|
||||
} else {
|
||||
val doubleValue = trimmed.toDoubleOrNull()
|
||||
if (doubleValue == null || doubleValue.isInfinite())
|
||||
String::class
|
||||
else Double::class
|
||||
}
|
||||
else -> String::class
|
||||
}
|
||||
val finalValue = when (typeSpec) {
|
||||
String::class -> "\"$valueString\""
|
||||
Long::class -> if (trimmed.endsWith("L")) trimmed else "${trimmed}L"
|
||||
else -> trimmed
|
||||
}
|
||||
|
||||
return typeSpec to finalValue
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize property keys for code generation.
|
||||
* @receiver [PropertyMap]
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Gropify - A type-safe and modern properties plugin for Gradle.
|
||||
* Copyright (C) 2019 HighCapable
|
||||
* https://github.com/HighCapable/Gropify
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is created by fankes on 2025/11/13.
|
||||
*/
|
||||
package com.highcapable.gropify.plugin.generator.extension
|
||||
|
||||
import com.highcapable.gropify.internal.error
|
||||
import com.highcapable.gropify.plugin.Gropify
|
||||
import com.highcapable.gropify.utils.extension.isNumeric
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Create [PropertyTypeValue] from [String] value.
|
||||
* @receiver [String]
|
||||
* @param autoConversion whether to enable auto conversion.
|
||||
* @return [PropertyTypeValue]
|
||||
*/
|
||||
internal fun String.createTypeValue(autoConversion: Boolean): PropertyTypeValue {
|
||||
var isStringType = false
|
||||
val valueString = replace("\n", "\\n")
|
||||
.replace("\r", "\\r")
|
||||
.replace("\\", "\\\\")
|
||||
.let {
|
||||
if (autoConversion && (it.startsWith("\"") && it.endsWith("\"") || it.startsWith("'") && it.endsWith("'"))) {
|
||||
isStringType = true
|
||||
it.drop(1).dropLast(1)
|
||||
} else it.replace("\"", "\\\"")
|
||||
}
|
||||
|
||||
if (!autoConversion) return PropertyTypeValue(this, "\"$valueString\"", String::class)
|
||||
|
||||
val trimmed = valueString.trim()
|
||||
val typeSpec = when {
|
||||
isStringType -> String::class
|
||||
trimmed.toBooleanStrictOrNull() != null -> Boolean::class
|
||||
trimmed.isNumeric() ->
|
||||
if (!trimmed.contains(".")) {
|
||||
val longValue = trimmed.toLongOrNull()
|
||||
when (longValue) {
|
||||
null -> String::class
|
||||
in Int.MIN_VALUE..Int.MAX_VALUE -> Int::class
|
||||
else -> Long::class
|
||||
}
|
||||
} else {
|
||||
val doubleValue = trimmed.toDoubleOrNull()
|
||||
if (doubleValue == null || doubleValue.isInfinite())
|
||||
String::class
|
||||
else Double::class
|
||||
}
|
||||
else -> String::class
|
||||
}
|
||||
val finalValue = when (typeSpec) {
|
||||
String::class -> "\"$valueString\""
|
||||
Long::class -> if (trimmed.endsWith("L")) trimmed else "${trimmed}L"
|
||||
else -> trimmed
|
||||
}
|
||||
|
||||
return PropertyTypeValue(this, finalValue, typeSpec)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create [PropertyTypeValue] from [Any] value's type.
|
||||
* @receiver [Any]
|
||||
* @param autoConversion whether to enable auto conversion.
|
||||
* @return [PropertyTypeValue]
|
||||
*/
|
||||
internal fun Any.createTypeValueByType(autoConversion: Boolean): PropertyTypeValue {
|
||||
val typeSpec = this.javaClass.kotlin
|
||||
val valueString = toString()
|
||||
.replace("\n", "\\n")
|
||||
.replace("\r", "\\r")
|
||||
.replace("\\", "\\\\")
|
||||
.replace("\"", "\\\"")
|
||||
|
||||
val trimmed = valueString.trim()
|
||||
|
||||
val finalValue = if (autoConversion) when (typeSpec) {
|
||||
String::class, CharSequence::class -> "\"$trimmed\""
|
||||
Char::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."
|
||||
)
|
||||
} else "\"$valueString\""
|
||||
|
||||
return PropertyTypeValue(this.toString(), finalValue, typeSpec)
|
||||
}
|
||||
|
||||
/**
|
||||
* Property type value entity.
|
||||
*/
|
||||
internal data class PropertyTypeValue(
|
||||
val raw: String,
|
||||
val codeValue: String,
|
||||
val type: KClass<*>
|
||||
)
|
||||
Reference in New Issue
Block a user