diff --git a/LazyPeopleHttp-lib/build.gradle.kts b/LazyPeopleHttp-lib/build.gradle.kts index 4b5ef47..58d3359 100644 --- a/LazyPeopleHttp-lib/build.gradle.kts +++ b/LazyPeopleHttp-lib/build.gradle.kts @@ -148,70 +148,74 @@ android { } afterEvaluate { - tasks.findByName("signAndroidReleasePublication")!! - .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) - tasks.findByName("signIosArm64Publication")!! - .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) - tasks.findByName("signIosSimulatorArm64Publication")!! - .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) - tasks.findByName("signIosX64Publication")!! - .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) - tasks.findByName("signJsPublication")!! - .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) - tasks.findByName("signJvmPublication")!! - .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) - tasks.findByName("signKotlinMultiplatformPublication")!! - .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) - tasks.findByName("signIosArm64Publication")!! - .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) - tasks.findByName("signIosSimulatorArm64Publication")!! - .mustRunAfter(tasks.findByName("publishIosArm64PublicationToSonatypeRepository")) - tasks.findByName("signIosSimulatorArm64Publication")!! - .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) - tasks.findByName("signIosX64Publication")!! - .mustRunAfter(tasks.findByName("publishIosArm64PublicationToSonatypeRepository")) - tasks.findByName("signIosX64Publication")!! - .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) - tasks.findByName("signJsPublication")!! - .mustRunAfter(tasks.findByName("publishIosArm64PublicationToSonatypeRepository")) - tasks.findByName("signJsPublication")!! - .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) - tasks.findByName("signJvmPublication")!! - .mustRunAfter(tasks.findByName("publishIosArm64PublicationToSonatypeRepository")) - tasks.findByName("signJvmPublication")!! - .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) - tasks.findByName("signKotlinMultiplatformPublication")!! - .mustRunAfter(tasks.findByName("publishIosArm64PublicationToSonatypeRepository")) - tasks.findByName("signKotlinMultiplatformPublication")!! - .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) - tasks.findByName("signIosX64Publication")!! - .mustRunAfter(tasks.findByName("publishIosSimulatorArm64PublicationToSonatypeRepository")) - tasks.findByName("signJsPublication")!! - .mustRunAfter(tasks.findByName("publishIosSimulatorArm64PublicationToSonatypeRepository")) - tasks.findByName("signJvmPublication")!! - .mustRunAfter(tasks.findByName("publishIosSimulatorArm64PublicationToSonatypeRepository")) - tasks.findByName("signKotlinMultiplatformPublication")!! - .mustRunAfter(tasks.findByName("publishIosSimulatorArm64PublicationToSonatypeRepository")) - tasks.findByName("signJsPublication")!! - .mustRunAfter(tasks.findByName("publishIosX64PublicationToSonatypeRepository")) - tasks.findByName("signJvmPublication")!! - .mustRunAfter(tasks.findByName("publishIosX64PublicationToSonatypeRepository")) - tasks.findByName("signKotlinMultiplatformPublication")!! - .mustRunAfter(tasks.findByName("publishIosX64PublicationToSonatypeRepository")) - tasks.findByName("signJvmPublication")!! - .mustRunAfter(tasks.findByName("publishJsPublicationToSonatypeRepository")) - tasks.findByName("signKotlinMultiplatformPublication")!! - .mustRunAfter(tasks.findByName("publishJsPublicationToSonatypeRepository")) - tasks.findByName("signKotlinMultiplatformPublication")!! - .mustRunAfter(tasks.findByName("publishJvmPublicationToSonatypeRepository")) - tasks.findByName("signWasmJsPublication")!! - .mustRunAfter(tasks.findByName("publishKotlinMultiplatformPublicationToSonatypeRepository")) - tasks.findByName("signWasmJsPublication")!! - .mustRunAfter(tasks.findByName("publishJvmPublicationToSonatypeRepository")) - tasks.findByName("signWasmJsPublication")!! - .mustRunAfter(tasks.findByName("publishJsPublicationToSonatypeRepository")) - tasks.findByName("signWasmJsPublication")!! - .mustRunAfter(tasks.findByName("publishIosX64PublicationToSonatypeRepository")) - tasks.findByName("signWasmJsPublication")!! - .mustRunAfter(tasks.findByName("publishIosSimulatorArm64PublicationToSonatypeRepository")) + try { + tasks.findByName("signAndroidReleasePublication")!! + .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) + tasks.findByName("signIosArm64Publication")!! + .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) + tasks.findByName("signIosSimulatorArm64Publication")!! + .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) + tasks.findByName("signIosX64Publication")!! + .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) + tasks.findByName("signJsPublication")!! + .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) + tasks.findByName("signJvmPublication")!! + .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) + tasks.findByName("signKotlinMultiplatformPublication")!! + .mustRunAfter(tasks.findByName("publishAndroidDebugPublicationToSonatypeRepository")) + tasks.findByName("signIosArm64Publication")!! + .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) + tasks.findByName("signIosSimulatorArm64Publication")!! + .mustRunAfter(tasks.findByName("publishIosArm64PublicationToSonatypeRepository")) + tasks.findByName("signIosSimulatorArm64Publication")!! + .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) + tasks.findByName("signIosX64Publication")!! + .mustRunAfter(tasks.findByName("publishIosArm64PublicationToSonatypeRepository")) + tasks.findByName("signIosX64Publication")!! + .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) + tasks.findByName("signJsPublication")!! + .mustRunAfter(tasks.findByName("publishIosArm64PublicationToSonatypeRepository")) + tasks.findByName("signJsPublication")!! + .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) + tasks.findByName("signJvmPublication")!! + .mustRunAfter(tasks.findByName("publishIosArm64PublicationToSonatypeRepository")) + tasks.findByName("signJvmPublication")!! + .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) + tasks.findByName("signKotlinMultiplatformPublication")!! + .mustRunAfter(tasks.findByName("publishIosArm64PublicationToSonatypeRepository")) + tasks.findByName("signKotlinMultiplatformPublication")!! + .mustRunAfter(tasks.findByName("publishAndroidReleasePublicationToSonatypeRepository")) + tasks.findByName("signIosX64Publication")!! + .mustRunAfter(tasks.findByName("publishIosSimulatorArm64PublicationToSonatypeRepository")) + tasks.findByName("signJsPublication")!! + .mustRunAfter(tasks.findByName("publishIosSimulatorArm64PublicationToSonatypeRepository")) + tasks.findByName("signJvmPublication")!! + .mustRunAfter(tasks.findByName("publishIosSimulatorArm64PublicationToSonatypeRepository")) + tasks.findByName("signKotlinMultiplatformPublication")!! + .mustRunAfter(tasks.findByName("publishIosSimulatorArm64PublicationToSonatypeRepository")) + tasks.findByName("signJsPublication")!! + .mustRunAfter(tasks.findByName("publishIosX64PublicationToSonatypeRepository")) + tasks.findByName("signJvmPublication")!! + .mustRunAfter(tasks.findByName("publishIosX64PublicationToSonatypeRepository")) + tasks.findByName("signKotlinMultiplatformPublication")!! + .mustRunAfter(tasks.findByName("publishIosX64PublicationToSonatypeRepository")) + tasks.findByName("signJvmPublication")!! + .mustRunAfter(tasks.findByName("publishJsPublicationToSonatypeRepository")) + tasks.findByName("signKotlinMultiplatformPublication")!! + .mustRunAfter(tasks.findByName("publishJsPublicationToSonatypeRepository")) + tasks.findByName("signKotlinMultiplatformPublication")!! + .mustRunAfter(tasks.findByName("publishJvmPublicationToSonatypeRepository")) + tasks.findByName("signWasmJsPublication")!! + .mustRunAfter(tasks.findByName("publishKotlinMultiplatformPublicationToSonatypeRepository")) + tasks.findByName("signWasmJsPublication")!! + .mustRunAfter(tasks.findByName("publishJvmPublicationToSonatypeRepository")) + tasks.findByName("signWasmJsPublication")!! + .mustRunAfter(tasks.findByName("publishJsPublicationToSonatypeRepository")) + tasks.findByName("signWasmJsPublication")!! + .mustRunAfter(tasks.findByName("publishIosX64PublicationToSonatypeRepository")) + tasks.findByName("signWasmJsPublication")!! + .mustRunAfter(tasks.findByName("publishIosSimulatorArm64PublicationToSonatypeRepository")) + } catch (e: Exception) { + e.printStackTrace() + } } \ No newline at end of file diff --git a/LazyPeopleHttp/build.gradle.kts b/LazyPeopleHttp/build.gradle.kts index 98b516c..2fbf4d3 100644 --- a/LazyPeopleHttp/build.gradle.kts +++ b/LazyPeopleHttp/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("convention.publication") + kotlin("plugin.serialization") version kotlinVersion } group = "io.github.ltttttttttttt" @@ -25,11 +26,16 @@ kotlin { implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion") implementation(project(":LazyPeopleHttp-lib")) implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable:$kotlinVersion") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationJsonVersion") } } val jvmTest by getting } } -tasks.findByName("signKotlinMultiplatformPublication")!! - .dependsOn(tasks.findByName("publishJvmPublicationToSonatypeRepository")) \ No newline at end of file +try { + tasks.findByName("signKotlinMultiplatformPublication")!! + .dependsOn(tasks.findByName("publishJvmPublicationToSonatypeRepository")) +} catch (e: Exception) { + e.printStackTrace() +} \ No newline at end of file diff --git a/LazyPeopleHttp/src/jvmMain/kotlin/com/lt/lazy_people_http/options/CustomizeOutputFileBean.kt b/LazyPeopleHttp/src/jvmMain/kotlin/com/lt/lazy_people_http/options/CustomizeOutputFileBean.kt new file mode 100644 index 0000000..333629b --- /dev/null +++ b/LazyPeopleHttp/src/jvmMain/kotlin/com/lt/lazy_people_http/options/CustomizeOutputFileBean.kt @@ -0,0 +1,145 @@ +package com.lt.lazy_people_http.options + +import kotlinx.serialization.* + +/** + * creator: lt 2024/11/25 lt.dygzs@qq.com + * effect : 自定义输出文件配置 + * warning: 属性替换规则参考[ReplaceRule] + */ +interface CustomizeOutputFileBean { + //生成的文件名 + val fileName: String + + //生成文件的扩展名 + val extensionName: String + + //文件顶部内容(导包,类声明等) + val fileTopContent: String + + //文件底部内容(类结尾括号,扩展方法等) + val fileBottomContent: String + + //suspend方法内容(方法的声明和方法体) + val suspendFunContent: FunctionBean + + //方法内容(方法的声明和方法体) + val funContent: FunctionBean +} + +/** + * 属性替换规则 + */ +object ReplaceRule { + /*类级别*/ + fun String._packageName(packageName: String) = replace("##packageName##", packageName)//包名 + fun String._className(className: String) = replace("##className##", className)//生成后的类名 + fun String._originalClassName(originalClassName: String) = replace("##originalClassName##", originalClassName)//原类名 + + /*方法级*/ + fun String._functionName(functionName: String) = replace("##functionName##", functionName)//方法名 + fun String._funParameter(funParameter: String) = replace("##funParameter##", funParameter)//方法参数及类型 + fun String._returnType(returnType: String) = replace("##returnType##", returnType)//方法返回值类型 + fun String._url(url: String) = replace("##url##", url)//请求url + fun String._queryParameter(queryParameter: String) = replace("##queryParameter##", queryParameter)//query请求参数 + fun String._fieldParameter(fieldParameter: String) = replace("##fieldParameter##", fieldParameter)//field请求参数 + fun String._runtimeParameter(runtimeParameter: String) = + replace("##runtimeParameter##", runtimeParameter)//运行时设置的请求参数 + + fun String._type(type: String) = replace("##type##", type)//需要被解析的类型,如果是suspend方法则与returnType一致 + fun String._requestMethod(requestMethod: String) = replace("##requestMethod##", requestMethod)//网络请求使用的方法 + fun String._headers(headers: String) = replace("##headers##", headers)//注解中声明的请求头 + fun String._functionAnnotations(functionAnnotations: String) = + replace("##functionAnnotations##", functionAnnotations)//方法上所有声明的注解 + + fun String._responseName(responseName: String) = replace("##responseName##", responseName)//自定义的返回值类型,比如Flow + + /*参数级*/ + fun String._kt(key: String, type: String) = replace("##key##", key).replace("##type##", type)//参数及类型 + fun String._kv(key: String, value: String) = replace("##key##", key).replace("##value##", value)//参数名及参数值 + +} + +@Serializable +class CustomizeOutputFileBeanImpl( + override val fileName: String = "##className##", + override val extensionName: String = "kt", + override val fileTopContent: String = "package ##packageName##\n" + + "\n" + + "import com.lt.lazy_people_http._lazyPeopleHttpFlatten\n" + + "import com.lt.lazy_people_http.call.Call\n" + + "import com.lt.lazy_people_http.call.CallCreator\n" + + "import com.lt.lazy_people_http.config.LazyPeopleHttpConfig\n" + + "import com.lt.lazy_people_http.request.RequestMethod\n" + + "import com.lt.lazy_people_http.service.HttpServiceImpl\n" + + "import kotlin.reflect.typeOf\n" + + "\n" + + "class ##className##(\n" + + " val config: LazyPeopleHttpConfig,\n" + + ") : ##originalClassName##, HttpServiceImpl {\n" + + " private inline fun T?._toJson() = CallCreator.parameterToJson(config, this)\n\n", + override val fileBottomContent: String = "}\n\n" + + "fun kotlin.reflect.KClass<##originalClassName##>.createService(config: LazyPeopleHttpConfig): ##originalClassName## =\n" + + " ##className##(config)", + override val suspendFunContent: FunctionBean = FunctionBean( + " override suspend fun ##functionName##(##funParameter##): ##returnType## {\n" + + " return CallCreator.createResponse>(\n" + + " config,\n" + + " \"##url##\",\n" + + " ##queryParameter##,\n" + + " ##fieldParameter##,\n" + + " ##runtimeParameter##,\n" + + " typeOf<##type##>(),\n" + + " ##requestMethod##,\n" + + " ##headers##,\n" + + " ##functionAnnotations##,\n" + + " ##responseName##,\n" + + " ).await()\n" + + " }\n\n", + ), + override val funContent: FunctionBean = FunctionBean( + " override fun ##functionName##(##funParameter##): ##returnType## {\n" + + " return CallCreator.createResponse(\n" + + " config,\n" + + " \"##url##\",\n" + + " ##queryParameter##,\n" + + " ##fieldParameter##,\n" + + " ##runtimeParameter##,\n" + + " typeOf<##type##>(),\n" + + " ##requestMethod##,\n" + + " ##headers##,\n" + + " ##functionAnnotations##,\n" + + " ##responseName##,\n" + + " )\n" + + " }\n\n", + ), +) : CustomizeOutputFileBean + +/** + * 方法内容 + */ +@Serializable +class FunctionBean( + //方法内容 + val content: String, + //方法参数及类型 + val funParameterKT: String = "##key##: ##type##", + //query参数 + val queryParameter: ParameterBean = ParameterBean(), + //field参数 + val fieldParameter: ParameterBean = ParameterBean(), + //运行时参数 + val runtimeParameter: ParameterBean = ParameterBean(), + //请求头 + val header: ParameterBean = ParameterBean(), +) + +/** + * 参数内容 + */ +@Serializable +class ParameterBean( + val emptyValue: String = "null", + val arrayStart: String = "arrayOf(", + val arrayEnd: String = ")", +) \ No newline at end of file diff --git a/LazyPeopleHttp/src/jvmMain/kotlin/com/lt/lazy_people_http/options/KspOptions.kt b/LazyPeopleHttp/src/jvmMain/kotlin/com/lt/lazy_people_http/options/KspOptions.kt index e054a8d..28276ca 100644 --- a/LazyPeopleHttp/src/jvmMain/kotlin/com/lt/lazy_people_http/options/KspOptions.kt +++ b/LazyPeopleHttp/src/jvmMain/kotlin/com/lt/lazy_people_http/options/KspOptions.kt @@ -12,9 +12,9 @@ internal class KspOptions(environment: SymbolProcessorEnvironment) { private val suffix = "WithLazyPeopleHttp"//后缀 private val options = environment.options private val isGetFunAnnotations = "getFunAnnotations$suffix" - private val createCallFunName = "createCallFunName$suffix" private val functionReplaceFrom = "functionReplaceFrom$suffix" private val functionReplaceTo = "functionReplaceTo$suffix" + private val customizeOutputFile = "customizeOutputFile$suffix" /** * 是否需要在请求信息[RequestInfo]中附带"获取方法和其参数以及返回值上的注解(不包含Type的注解)"的方式 @@ -22,12 +22,6 @@ internal class KspOptions(environment: SymbolProcessorEnvironment) { fun isGetFunAnnotations(): Boolean = options[isGetFunAnnotations] == "true" - /** - * 获取创建Call的方法名,可以自定义创建Call的子类 - */ - fun getCreateCallFunName(): String = - options[createCallFunName].ifNullOfEmpty { "CallCreator.createResponse" } - /** * 要将方法名的名称当做url时将某值替换为[functionReplaceTo] */ @@ -37,4 +31,9 @@ internal class KspOptions(environment: SymbolProcessorEnvironment) { * 要将方法名的名称当做url时将[functionReplaceFrom]替换为设置的值 */ fun getFunctionReplaceTo(): String = options[functionReplaceTo] ?: "" + + /** + * 自定义输出文件的规则,参考[CustomizeOutputFileBean],需要一个json文件,内容是List + */ + fun getCustomizeOutputFile(): String = options[customizeOutputFile] ?: "" } \ No newline at end of file diff --git a/LazyPeopleHttp/src/jvmMain/kotlin/com/lt/lazy_people_http/provider/LazyPeopleHttpVisitor.kt b/LazyPeopleHttp/src/jvmMain/kotlin/com/lt/lazy_people_http/provider/LazyPeopleHttpVisitor.kt index 1881330..23e14fa 100644 --- a/LazyPeopleHttp/src/jvmMain/kotlin/com/lt/lazy_people_http/provider/LazyPeopleHttpVisitor.kt +++ b/LazyPeopleHttp/src/jvmMain/kotlin/com/lt/lazy_people_http/provider/LazyPeopleHttpVisitor.kt @@ -1,37 +1,30 @@ package com.lt.lazy_people_http.provider -import com.google.devtools.ksp.KspExperimental -import com.google.devtools.ksp.getAnnotationsByType -import com.google.devtools.ksp.getDeclaredFunctions -import com.google.devtools.ksp.processing.Dependencies -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.symbol.ClassKind -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSFunctionDeclaration -import com.google.devtools.ksp.symbol.KSValueParameter -import com.google.devtools.ksp.symbol.KSVisitorVoid -import com.google.devtools.ksp.symbol.Modifier -import com.google.devtools.ksp.symbol.Nullability -import com.lt.lazy_people_http.annotations.Field -import com.lt.lazy_people_http.annotations.FieldMap -import com.lt.lazy_people_http.annotations.GET -import com.lt.lazy_people_http.annotations.Header -import com.lt.lazy_people_http.annotations.POST -import com.lt.lazy_people_http.annotations.Query -import com.lt.lazy_people_http.annotations.QueryMap -import com.lt.lazy_people_http.annotations.Url -import com.lt.lazy_people_http.annotations.UrlMidSegment -import com.lt.lazy_people_http.appendText -import com.lt.lazy_people_http.getKSTypeArguments -import com.lt.lazy_people_http.getKSTypeInfo -import com.lt.lazy_people_http.getKSTypeOutermostName -import com.lt.lazy_people_http.getNewAnnotationString -import com.lt.lazy_people_http.montageUrl -import com.lt.lazy_people_http.options.KspOptions -import com.lt.lazy_people_http.options.MethodInfo -import com.lt.lazy_people_http.options.ParameterInfo -import com.lt.lazy_people_http.request.RequestMethod -import java.io.OutputStream +import com.google.devtools.ksp.* +import com.google.devtools.ksp.processing.* +import com.google.devtools.ksp.symbol.* +import com.lt.lazy_people_http.* +import com.lt.lazy_people_http.annotations.* +import com.lt.lazy_people_http.options.* +import com.lt.lazy_people_http.options.ReplaceRule._className +import com.lt.lazy_people_http.options.ReplaceRule._fieldParameter +import com.lt.lazy_people_http.options.ReplaceRule._funParameter +import com.lt.lazy_people_http.options.ReplaceRule._functionAnnotations +import com.lt.lazy_people_http.options.ReplaceRule._functionName +import com.lt.lazy_people_http.options.ReplaceRule._headers +import com.lt.lazy_people_http.options.ReplaceRule._kt +import com.lt.lazy_people_http.options.ReplaceRule._originalClassName +import com.lt.lazy_people_http.options.ReplaceRule._packageName +import com.lt.lazy_people_http.options.ReplaceRule._queryParameter +import com.lt.lazy_people_http.options.ReplaceRule._requestMethod +import com.lt.lazy_people_http.options.ReplaceRule._responseName +import com.lt.lazy_people_http.options.ReplaceRule._returnType +import com.lt.lazy_people_http.options.ReplaceRule._runtimeParameter +import com.lt.lazy_people_http.options.ReplaceRule._type +import com.lt.lazy_people_http.options.ReplaceRule._url +import com.lt.lazy_people_http.request.* +import kotlinx.serialization.json.* +import java.io.* /** * creator: lt 2022/10/20 lt.dygzs@qq.com @@ -44,11 +37,11 @@ internal class LazyPeopleHttpVisitor( private val options = KspOptions(environment) private val isGetFunAnnotations = options.isGetFunAnnotations() - private val createCallFunName = options.getCreateCallFunName() private val functionReplaceFrom = options.getFunctionReplaceFrom() private val functionReplaceTo = options.getFunctionReplaceTo() private val isFunctionNameReplace =//是否对方法名进行替换 functionReplaceFrom.isNotEmpty() && functionReplaceTo.isNotEmpty() + private val json = Json { ignoreUnknownKeys = true } /** * 访问class的声明 @@ -60,14 +53,26 @@ internal class LazyPeopleHttpVisitor( val className = "_${originalClassName}ServiceImpl" if (classDeclaration.classKind != ClassKind.INTERFACE) throw RuntimeException("LazyPeopleHttpService can only decorate interface") - val file = environment.codeGenerator.createNewFile( - Dependencies( - true, - classDeclaration.containingFile!! - ), packageName, className - ) - writeFile(file, packageName, className, originalClassName, classDeclaration) - file.close() + + val jsonFile = File(options.getCustomizeOutputFile()) + val beans = ArrayList() + if (!jsonFile.exists()) + beans.add(CustomizeOutputFileBeanImpl()) + else + beans.addAll(json.decodeFromString>(jsonFile.readText())) + beans.forEach { bean -> + val file = environment.codeGenerator.createNewFile( + Dependencies( + true, + classDeclaration.containingFile!! + ), + packageName, + bean.fileName._className(className)._originalClassName(originalClassName), + bean.extensionName, + ) + writeFile(file, packageName, className, originalClassName, classDeclaration, bean) + file.close() + } } //向文件中写入完整内容 @@ -76,38 +81,24 @@ internal class LazyPeopleHttpVisitor( packageName: String, className: String, originalClassName: String, - classDeclaration: KSClassDeclaration + classDeclaration: KSClassDeclaration, + bean: CustomizeOutputFileBean, ) { file.appendText( - "package $packageName\n" + - "\n" + - "import com.lt.lazy_people_http._lazyPeopleHttpFlatten\n" + - "import com.lt.lazy_people_http.call.Call\n" + - "import com.lt.lazy_people_http.call.CallCreator\n" + - "import com.lt.lazy_people_http.config.LazyPeopleHttpConfig\n" + - "import com.lt.lazy_people_http.request.RequestMethod\n" + - "import com.lt.lazy_people_http.service.HttpServiceImpl\n" + - "import kotlin.reflect.typeOf\n" + - "\n" + - "class $className(\n" + - " val config: LazyPeopleHttpConfig,\n" + - ") : $originalClassName, HttpServiceImpl {\n" + - " private inline fun T?._toJson() = CallCreator.parameterToJson(config, this)\n\n" + bean.fileTopContent._packageName(packageName)._className(className)._originalClassName(originalClassName) ) - writeFunction(file, classDeclaration) + writeFunction(file, classDeclaration, bean) file.appendText( - "}\n\n" + - "fun kotlin.reflect.KClass<$originalClassName>.createService(config: LazyPeopleHttpConfig): $originalClassName =\n" + - " $className(config)" + bean.fileBottomContent._className(className)._originalClassName(originalClassName) ) } //向文件中写入变换后的函数 - private fun writeFunction(file: OutputStream, classDeclaration: KSClassDeclaration) { + private fun writeFunction(file: OutputStream, classDeclaration: KSClassDeclaration, bean: CustomizeOutputFileBean) { classDeclaration.superTypes.mapNotNull { it.resolve().declaration as? KSClassDeclaration }.forEach { - writeFunction(file, it) + writeFunction(file, it, bean) } classDeclaration.getDeclaredFunctions().filter { it.isAbstract @@ -127,35 +118,38 @@ internal class LazyPeopleHttpVisitor( } val typeOf = if (isSuspendFun) returnType else getKSTypeArguments(it.returnType!!).first() - val headers = getHeaders(it) - val parameterInfo = getParameters(it, methodInfo.method) + val funBean = if (isSuspendFun) bean.suspendFunContent else bean.funContent + val headers = getHeaders(it, funBean.header) + val parameterInfo = + getParameters(it, methodInfo.method, funBean) var url = methodInfo.url parameterInfo.replaceUrlFunction?.forEach { url = url.replace(it.key, "\$${it.value}") } val functionAnnotations = getFunctionAnnotations(it) - file.appendText(" override ${if (isSuspendFun) "suspend " else ""}fun $functionName(${parameterInfo.funParameter}): $returnType {\n") - file.appendText( - " return $createCallFunName${if (isSuspendFun) ">" else ""}(\n" + - " config,\n" + - " \"$url\",\n" + - " ${parameterInfo.queryParameter},\n" + - " ${parameterInfo.fieldParameter},\n" + - " ${parameterInfo.runtimeParameter},\n" + - " typeOf<$typeOf>(),\n" + - " ${if (methodInfo.method == null) "null" else "RequestMethod.${methodInfo.method}"},\n" + - " $headers,\n" + - " ${if (functionAnnotations.isEmpty()) "null" else "arrayOf($functionAnnotations)"},\n" + - " $responseName,\n" + - " )${if (isSuspendFun) ".await()" else ""}\n" + - " }\n\n" - ) + val funContent = if (isSuspendFun) { + bean.suspendFunContent + } else { + bean.funContent + }.content._functionName(functionName) + ._funParameter(parameterInfo.funParameter) + ._returnType(returnType) + ._url(url) + ._queryParameter(parameterInfo.queryParameter) + ._fieldParameter(parameterInfo.fieldParameter) + ._runtimeParameter(parameterInfo.runtimeParameter) + ._type(typeOf) + ._requestMethod(if (methodInfo.method == null) "null" else "RequestMethod.${methodInfo.method}") + ._headers(headers) + ._functionAnnotations(if (functionAnnotations.isEmpty()) "null" else "arrayOf($functionAnnotations)") + ._responseName(responseName.toString()) + file.appendText(funContent) } } //获取方法的参数和请求参数 - private fun getParameters(it: KSFunctionDeclaration, method: RequestMethod?): ParameterInfo { + private fun getParameters(it: KSFunctionDeclaration, method: RequestMethod?, funBean: FunctionBean): ParameterInfo { //如果没有参数 if (it.parameters.isEmpty()) return ParameterInfo("", "null", "null", "null", null) //有参数的话就将参数拆为:方法参数,query参数,field参数,和只有运行时才能处理的参数 @@ -167,7 +161,7 @@ internal class LazyPeopleHttpVisitor( it.parameters.forEach { val funPName = it.name!!.asString() val type = getKSTypeInfo(it.type).toString() - funPList.add("$funPName: $type") + funPList.add(funBean.funParameterKT._kt(funPName,type)) getParameterInfo(it, funPName, queryPList, fieldPList, runtimePList, replaceUrlMap) } //处理方法加了注解,但参数没加注解的情况 @@ -187,17 +181,17 @@ internal class LazyPeopleHttpVisitor( //将所有参数拼接成代码 return ParameterInfo( if (funPList.isEmpty()) "" else funPList.joinToString(), - if (queryPList.isEmpty()) "null" else queryPList.joinToString( - prefix = "arrayOf(", - postfix = ")" + if (queryPList.isEmpty()) funBean.queryParameter.emptyValue else queryPList.joinToString( + prefix = funBean.queryParameter.arrayStart, + postfix = funBean.queryParameter.arrayEnd ), - if (fieldPList.isEmpty()) "null" else fieldPList.joinToString( - prefix = "arrayOf(", - postfix = ")" + if (fieldPList.isEmpty()) funBean.fieldParameter.emptyValue else fieldPList.joinToString( + prefix = funBean.fieldParameter.arrayStart, + postfix = funBean.fieldParameter.arrayEnd ), - if (runtimePList.isEmpty()) "null" else runtimePList.joinToString( - prefix = "arrayOf(", - postfix = ")" + if (runtimePList.isEmpty()) funBean.runtimeParameter.emptyValue else runtimePList.joinToString( + prefix = funBean.runtimeParameter.arrayStart, + postfix = funBean.runtimeParameter.arrayEnd ), replaceUrlMap, ) @@ -290,12 +284,12 @@ internal class LazyPeopleHttpVisitor( //获取请求头的内容 @OptIn(KspExperimental::class) - private fun getHeaders(it: KSFunctionDeclaration): String { + private fun getHeaders(it: KSFunctionDeclaration, header: ParameterBean): String { val list = it.getAnnotationsByType(Header::class).toList() - if (list.isEmpty()) return "null" + if (list.isEmpty()) return header.emptyValue return list.joinToString( - prefix = "arrayOf(", - postfix = ")" + prefix = header.arrayStart, + postfix = header.arrayEnd ) { "\"${it.name}\", \"${it.value}\"" } } diff --git a/README.md b/README.md index 43180c0..5b1c052 100644 --- a/README.md +++ b/README.md @@ -159,8 +159,8 @@ hf.postB("123").config { ksp { //Enable runtime configuration to obtain all annotations, call [RequestInfo # functionAnnotations] when not enabled and always return null //arg("getFunAnnotationsWithLazyPeopleHttp", "true") - //Modify the method of creating a Call to return a custom Call - //arg("createCallFunNameWithLazyPeopleHttp", "CallAdapter.createCall2") + //Rules for customizing output files, refer to [CustomizeOutputFileBean], Need a JSON file, The content is List + //arg("customizeOutputFileWithLazyPeopleHttp", "${project.projectDir.absoluteFile}/customizeOutputFile.json") //When using the name of a method as a URL, replace a value with [functionReplaceTo] //arg("functionReplaceFromWithLazyPeopleHttp", "_") //When using the method name as a URL, replace [functionReplaceFrom] with the set value diff --git a/README_CN.md b/README_CN.md index a32ae4c..2a9da9a 100644 --- a/README_CN.md +++ b/README_CN.md @@ -159,8 +159,8 @@ hf.postB("123").config { ksp { //开启运行时配置获取所有注解的功能,不开启时调用[RequestInfo#functionAnnotations]始终返回null //arg("getFunAnnotationsWithLazyPeopleHttp", "true") - //修改创建Call的方法,来返回自定义的Call - //arg("createCallFunNameWithLazyPeopleHttp", "CallAdapter.createCall2") + //自定义输出文件的规则,参考[CustomizeOutputFileBean],需要一个json文件,内容是List + //arg("customizeOutputFileWithLazyPeopleHttp", "${project.projectDir.absoluteFile}/customizeOutputFile.json") //要将方法名的名称当做url时将某值替换为[functionReplaceTo] //arg("functionReplaceFromWithLazyPeopleHttp", "_") //要将方法名的名称当做url时将[functionReplaceFrom]替换为设置的值 diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 4b4ae84..b30e029 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -20,4 +20,4 @@ const val ktorVersion = "3.0.0"//ktor版本 const val serializationJsonVersion = "1.6.3"//json序列号版本 const val kspVersion = "$kotlinVersion-1.0.21"//ksp版本 -const val mVersion = "2.0.2"//此库的版本 \ No newline at end of file +const val mVersion = "2.1.1"//此库的版本 \ No newline at end of file diff --git a/common/build.gradle.kts b/common/build.gradle.kts index df9adae..b287343 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,3 +1,8 @@ +import org.gradle.api.JavaVersion +import org.gradle.api.Task +import org.gradle.api.tasks.Delete +import java.io.File + plugins { kotlin("multiplatform") id("org.jetbrains.compose") @@ -106,9 +111,9 @@ kotlin { } ksp { arg("getFunAnnotationsWithLazyPeopleHttp", "true") - //arg("createCallFunNameWithLazyPeopleHttp", "CallAdapter.createCall2") arg("functionReplaceFromWithLazyPeopleHttp", "_") arg("functionReplaceToWithLazyPeopleHttp", "/") + arg("customizeOutputFileWithLazyPeopleHttp", "${project.projectDir.absoluteFile}/customizeOutputFile.json") } } @@ -134,4 +139,15 @@ tasks.register("clearBuild") { doLast { delete(buildDir) } +} + +tasks.register("clearKsp") { + doFirst { + delete(File(buildDir, "generated/ksp").absolutePath) + } +} + +tasks.register("runKsp") { + dependsOn("clearKsp") + .dependsOn("kspCommonMainKotlinMetadata") } \ No newline at end of file diff --git a/common/customizeOutputFile.json b/common/customizeOutputFile.json new file mode 100644 index 0000000..5960fc9 --- /dev/null +++ b/common/customizeOutputFile.json @@ -0,0 +1,57 @@ +[ + { + }, + { + "extensionName": "js", + "fileTopContent": "import { HttpRequest } from \"../util/HttpUtil\";\n\nclass ##className## {\n\tfunction _toJson(value) {\n\t\tif (value == undefined || value == null)\n\t\t\treturn value\n\t\tswitch (typeof(value)) {\n\t\t\tcase \"number\":\n\t\t\tcase \"string\":\n\t\t\tcase \"boolean\":\n\t\t\t\treturn value.toString()\n\t\t\tdefault:\n\t\t\t\treturn JSON.stringify(value)\n\t\t}\n\t}\n\n", + "fileBottomContent": "}", + "suspendFunContent": { + "content": "\tfunction ##functionName##(##funParameter##) {\n\t\treturn HttpRequest({\n\t\t\turl: \"##url##\",\n\t\t\tdataArray: [...##queryParameter##, ...##fieldParameter##, ...##runtimeParameter##],\n method: ##requestMethod##,\n headerArray:##headers##,\n\t\t\tannotations: '##functionAnnotations##',\n\t\t})\n\t}\n\n", + "funParameterKT": "##key##", + "queryParameter": { + "emptyValue": "[]", + "arrayStart": "[", + "arrayEnd": "]" + }, + "fieldParameter": { + "emptyValue": "[]", + "arrayStart": "[", + "arrayEnd": "]" + }, + "runtimeParameter": { + "emptyValue": "[]", + "arrayStart": "[", + "arrayEnd": "]" + }, + "header": { + "emptyValue": "[]", + "arrayStart": "[", + "arrayEnd": "]" + } + }, + "funContent": { + "content": "\tfunction ##functionName##(##funParameter##) {\n\t\treturn HttpRequest({\n\t\t\turl: \"##url##\",\n\t\t\tdataArray: [...##queryParameter##, ...##fieldParameter##, ...##runtimeParameter##],\n method: ##requestMethod##,\n headerArray:##headers##,\n\t\t\tannotations: '##functionAnnotations##',\n\t\t})\n\t}\n\n", + "funParameterKT": "##key##", + "queryParameter": { + "emptyValue": "[]", + "arrayStart": "[", + "arrayEnd": "]" + }, + "fieldParameter": { + "emptyValue": "[]", + "arrayStart": "[", + "arrayEnd": "]" + }, + "runtimeParameter": { + "emptyValue": "[]", + "arrayStart": "[", + "arrayEnd": "]" + }, + "header": { + "emptyValue": "[]", + "arrayStart": "[", + "arrayEnd": "]" + } + } + } +] \ No newline at end of file