![JAR search and dependency download from the Maven repository](/logo.png)
com.therouter.ksp.TheRouterSymbolProcessor.kt Maven / Gradle / Ivy
package com.therouter.ksp
import com.google.devtools.ksp.containingFile
import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.symbol.FunctionKind
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSDeclaration
import com.google.devtools.ksp.symbol.KSFile
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.google.devtools.ksp.symbol.KSPropertyDeclaration
import com.google.devtools.ksp.symbol.KSType
import com.therouter.app.flowtask.lifecycle.FlowTask
import com.therouter.apt.ActionInterceptorItem
import com.therouter.apt.AutowiredItem
import com.therouter.apt.BuildConfig
import com.therouter.apt.FlowTaskItem
import com.therouter.apt.KEY_USE_EXTEND
import com.therouter.apt.PACKAGE
import com.therouter.apt.PREFIX_ROUTER_MAP
import com.therouter.apt.PREFIX_SERVICE_PROVIDER
import com.therouter.apt.PROPERTY_FILE
import com.therouter.apt.RouteItem
import com.therouter.apt.STR_TRUE
import com.therouter.apt.SUFFIX_AUTOWIRED
import com.therouter.apt.ServiceProviderItem
import com.therouter.apt.duplicateRemove
import com.therouter.apt.gson
import com.therouter.inject.ServiceProvider
import com.therouter.router.Autowired
import com.therouter.router.Route
import com.therouter.router.action.ActionInterceptor
import java.io.FileInputStream
import java.io.PrintStream
import java.lang.StringBuilder
import java.util.HashMap
import java.util.Locale
import java.util.Properties
import kotlin.collections.ArrayList
/**
* Created by ZhangTao on 17/8/11.
*/
class TheRouterSymbolProcessor(
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger
) : SymbolProcessor {
private var sourcePath = ""
private val routeDependencies = mutableSetOf()
private val autoWiredDependencies = mutableSetOf()
private val serviceProviderDependencies = mutableSetOf()
override fun process(resolver: Resolver): List {
routeDependencies.clear()
autoWiredDependencies.clear()
serviceProviderDependencies.clear()
genRouterMapFile(parseRoute(resolver))
genAutowiredFile(parseAutowired(resolver))
val providerItemList = parseServiceProvider(resolver)
val flowTaskList = parseFlowTask(resolver)
val actionInterceptorList = parseActionInterceptor(resolver)
genServiceProviderFile(providerItemList, flowTaskList, actionInterceptorList)
return emptyList()
}
private fun parseRoute(resolver: Resolver): List {
val list: ArrayList = ArrayList()
resolver.getSymbolsWithAnnotation(Route::class.java.name).forEach {
it.containingFile?.let { file ->
routeDependencies.add(file)
}
it.accept(RouteVisitor(list), Unit)
}
return list
}
inner class RouteVisitor(private val list: ArrayList) : TheRouterVisitor(logger) {
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
super.visitClassDeclaration(classDeclaration, data)
sourcePath = getSourcePath(classDeclaration)
classDeclaration.annotations.forEach { annotation ->
val routeItem = RouteItem()
routeItem.className = classDeclaration.qualifiedName?.asString()
annotation.arguments.forEach { arg ->
when (arg.name?.asString()) {
"path" -> routeItem.path = "${arg.value}"
"action" -> routeItem.action = "${arg.value}"
"description" -> routeItem.description = "${arg.value}"
"params" -> {
if (arg.value is Array<*>) {
require((arg.value as Array<*>).size % 2 == 0) { "${routeItem.className} @Route(params) is not key value pairs" }
var k: String? = null
for (kv in arg.value as Array<*>) {
if (k == null) {
require(kv != null) { "${routeItem.className} @Route(params) key is null" }
k = "$kv"
} else {
routeItem.params[k] = "$kv"
k = null
}
}
} else if (arg.value is java.util.ArrayList<*>) {
require((arg.value as java.util.ArrayList<*>).size % 2 == 0) { "${routeItem.className} @Route(params) is not key value pairs" }
var k: String? = null
for (kv in arg.value as java.util.ArrayList<*>) {
if (k == null) {
require(kv != null) { "${routeItem.className} @Route(params) key is null" }
k = "$kv"
} else {
routeItem.params[k] = "$kv"
k = null
}
}
}
}
}
}
if (routeItem.path.isNotEmpty() && !routeItem.className.isNullOrEmpty()) {
list.add(routeItem)
}
}
}
}
private fun genRouterMapFile(pageList: List) {
if (pageList.isEmpty()) {
return
}
val routePagelist = duplicateRemove(pageList)
// 确保只要编译的软硬件环境不变,类名就不会改变
val className = PREFIX_ROUTER_MAP + kotlin.math.abs(
if (sourcePath.isEmpty()) {
routePagelist[0].className?.hashCode() ?: routePagelist[0].path.hashCode()
} else {
sourcePath.hashCode()
}
)
val json = gson.toJson(routePagelist)
var ps: PrintStream? = null
try {
val dependencies = Dependencies(aggregating = true, *routeDependencies.toTypedArray())
ps = PrintStream(codeGenerator.createNewFile(dependencies, PACKAGE, className))
ps.println("@file:JvmName(\"$className\")")
ps.println("package $PACKAGE")
ps.println()
ps.println("/**")
ps.println(" * Generated code, Don't modify!!!")
ps.println(" * Created by kymjs, and KSP Version is ${BuildConfig.VERSION}.")
ps.println(" * JDK Version is ${System.getProperty("java.version")}.")
ps.println(" */")
ps.println("@androidx.annotation.Keep")
ps.println("class $className : com.therouter.router.IRouterMapAPT {")
ps.println()
ps.println("\tcompanion object { ")
ps.println()
ps.println("\tconst val TAG = \"Created by kymjs, and KSP Version is ${BuildConfig.VERSION}.\"")
ps.println("\tconst val THEROUTER_APT_VERSION = \"${BuildConfig.VERSION}\"")
val routeMapJson = json.replace("\"", "\\\"")
ps.println("\tconst val ROUTERMAP = \"$routeMapJson\"")
ps.println()
ps.println("\t@JvmStatic")
ps.println("\tfun addRoute() {")
var i = 0
for (item in routePagelist) {
i++
ps.println("\t\tval item$i = com.therouter.router.RouteItem(\"${item.path}\",\"${item.className}\",\"${item.action}\",\"${item.description}\")")
item.params.keys.forEach {
ps.println("\t\titem$i.addParams(\"$it\", \"${item.params[it]}\")")
}
ps.println("\t\tcom.therouter.router.addRouteItem(item$i)")
}
ps.println("\t}")
ps.println("\t}")
ps.println("}")
ps.flush()
} finally {
ps?.close()
}
}
private fun parseAutowired(resolver: Resolver): Map> {
val map = HashMap>()
resolver.getSymbolsWithAnnotation(Autowired::class.java.name).forEach {
it.containingFile?.let { file ->
autoWiredDependencies.add(file)
}
it.accept(AutowiredVisitor(map), Unit)
}
return map
}
inner class AutowiredVisitor(private val map: HashMap>) :
TheRouterVisitor(logger) {
override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) {
super.visitPropertyDeclaration(property, data)
sourcePath = getSourcePath(property)
property.annotations.forEach { annotation ->
val autowiredItem = AutowiredItem()
autowiredItem.fieldName = property.simpleName.asString()
autowiredItem.className = property.parentDeclaration?.qualifiedName?.asString() ?: property.packageName.asString()
autowiredItem.classNameAndTypeParameters = autowiredItem.className
property.parentDeclaration?.typeParameters?.size?.let { size ->
if (size > 0) {
val classNameBuilder = StringBuilder(autowiredItem.className).append("<")
for (i in 0 until size) {
classNameBuilder.append("*")
if (i != size - 1) {
classNameBuilder.append(",")
}
}
classNameBuilder.append(">")
autowiredItem.classNameAndTypeParameters = classNameBuilder.toString()
}
}
autowiredItem.type = getFieldType(property.type.resolve())
annotation.arguments.forEach { arg ->
when (arg.name?.asString()) {
"name" -> {
var key = "${arg.value}"
if (key.isBlank()) {
key = property.simpleName.asString()
}
autowiredItem.key = key
}
"args" -> autowiredItem.args = "${arg.value}"
"id" -> autowiredItem.id = "${arg.value ?: 0}".toInt()
"required" -> {
autowiredItem.required = "${arg.value}".equals("true", ignoreCase = true)
}
"description" -> autowiredItem.description = "${arg.value}"
}
}
var list = map[autowiredItem.className]
if (list == null) {
list = ArrayList()
}
list.add(autowiredItem)
list.sort()
map[autowiredItem.className] = list
}
}
}
private fun getFieldType(type: KSType?): String =
if (type != null && type.arguments.isNotEmpty()) {
val classNameBuilder = StringBuilder(type.declaration.qualifiedName?.asString()).append("<")
type.arguments.forEach {
classNameBuilder.append(getFieldType(it.type?.resolve())).append(",")
}
classNameBuilder.deleteCharAt(classNameBuilder.length - 1)
classNameBuilder.append(">")
classNameBuilder.toString()
} else {
type?.declaration?.qualifiedName?.asString() ?: ""
}
private fun genAutowiredFile(pageMap: Map>) {
val keyList = ArrayList(pageMap.keys)
// 做一次排序,确保只要map成员没有变化,输出文件内容的顺序就没有变化
keyList.sort()
for (key in keyList) {
val fullClassName = key + SUFFIX_AUTOWIRED
val fullClassNameAndTypeParameters = pageMap[key]?.get(0)?.classNameAndTypeParameters ?: key
val simpleName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1)
val pkgName = fullClassName.substring(0, fullClassName.lastIndexOf('.'))
var ps: PrintStream? = null
try {
val dependencies = Dependencies(aggregating = false, *autoWiredDependencies.toTypedArray())
ps = PrintStream(codeGenerator.createNewFile(dependencies, pkgName, simpleName))
ps.println("@file:JvmName(\"$simpleName\")")
ps.println(String.format("package %s", pkgName))
ps.println()
ps.println("/**")
ps.println(" * Generated code, Don't modify!!!")
ps.println(" * Created by kymjs, and KSP Version is ${BuildConfig.VERSION}.")
ps.println(" * JDK Version is ${System.getProperty("java.version")}.")
ps.println(" */")
ps.println("@androidx.annotation.Keep")
ps.println(String.format("object %s {", simpleName))
ps.println("\t@JvmStatic")
ps.println("\tval TAG = \"Created by kymjs, and KSP Version is ${BuildConfig.VERSION}.\"")
ps.println("\t@JvmStatic")
ps.println("\tval THEROUTER_APT_VERSION = \"${BuildConfig.VERSION}\"")
ps.println()
ps.println("\t@JvmStatic")
ps.println("\tfun autowiredInject(obj: Any) {")
ps.println(String.format("\t\tif (obj is %s) {", fullClassNameAndTypeParameters))
ps.println(String.format("\t\tval target = obj as %s", fullClassNameAndTypeParameters))
ps.println()
ps.println("\t\tfor (parser in com.therouter.TheRouter.parserList) {")
for ((i, item) in pageMap[key]!!.withIndex()) {
var type = transformNumber(item.type)
if (!type.endsWith('?')) {
type += "?"
}
val variableName = "variableName$i"
ps.println("\t\t\ttry {")
ps.println(
String.format(
"\t\t\t\tval %s: %s = parser.parse(\"%s\", target, com.therouter.router.AutowiredItem(\"%s\",\"%s\",%s,\"%s\",\"%s\",\"%s\",%s,\"%s\"))",
variableName, type,
item.type,
item.type,
item.key,
item.id,
item.args,
item.className,
item.fieldName,
item.required,
item.description
)
)
ps.println("\t\t\t\tif ($variableName != null){")
ps.println("\t\t\t\t\t// ${item.description}")
ps.println(String.format("\t\t\t\t\ttarget.%s = $variableName", item.fieldName))
ps.println("\t\t\t\t}")
ps.println("\t\t\t} catch (e: Exception) {")
ps.println("\t\t\t\tif (com.therouter.TheRouter.isDebug) { e.printStackTrace() }")
ps.println("\t\t\t}")
}
ps.println("\t\t} // for end")
ps.println()
ps.println("\t\t}")
ps.println("\t}")
ps.println("}")
ps.flush()
} finally {
ps?.close()
}
}
}
private fun parseServiceProvider(resolver: Resolver): ArrayList {
val list: ArrayList = ArrayList()
resolver.getSymbolsWithAnnotation(ServiceProvider::class.java.name).forEach {
it.containingFile?.let { file ->
serviceProviderDependencies.add(file)
}
it.accept(ServiceProviderVisitor(list), Unit)
}
return list
}
inner class ServiceProviderVisitor(private val list: ArrayList) :
TheRouterVisitor(logger) {
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
super.visitClassDeclaration(classDeclaration, data)
sourcePath = getSourcePath(classDeclaration)
classDeclaration.annotations.forEach { annotation ->
val serviceProviderItem = ServiceProviderItem(false)
serviceProviderItem.className =
classDeclaration.qualifiedName?.asString().toString()
serviceProviderItem.methodName = ""
annotation.arguments.forEach { arg ->
when (arg.name?.asString()) {
"returnType" -> {
if (arg.value is KSType) {
serviceProviderItem.returnType =
"${(arg.value as KSType).declaration.qualifiedName?.asString()}"
if (serviceProviderItem.returnType == ServiceProvider::class.java.name) {
serviceProviderItem.returnType = ""
}
}
}
"params" -> {
val params = ArrayList()
for (kv in arg.value as List<*>) {
if (kv is KSType) {
params.add(
transformNumber(
kv.declaration.qualifiedName?.asString() ?: ""
)
)
}
}
serviceProviderItem.params = params
}
}
}
if (serviceProviderItem.returnType.isBlank()) {
val list = classDeclaration.superTypes.toList()
if (list.isEmpty()) {
serviceProviderItem.returnType = serviceProviderItem.className
} else if (list.size == 1) {
list.forEach {
serviceProviderItem.returnType =
it.resolve().declaration.qualifiedName?.asString().toString()
}
} else {
val prop = Properties()
try {
val gradleProperties = FileInputStream(PROPERTY_FILE)
prop.load(gradleProperties)
} catch (e: Exception) {
}
if (!STR_TRUE.equals(
prop.getProperty(KEY_USE_EXTEND),
ignoreCase = true
)
) {
throw IllegalArgumentException(
serviceProviderItem.className +
" has multiple interfaces. Must to be specified returnType=XXX," +
" or configuration KEY_USE_EXTEND=true in gradle.properties"
)
} else {
serviceProviderItem.returnType = serviceProviderItem.className
}
}
}
list.add(serviceProviderItem)
}
}
override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
super.visitFunctionDeclaration(function, data)
sourcePath = getSourcePath(function)
if (function.functionKind != FunctionKind.STATIC && function.functionKind != FunctionKind.TOP_LEVEL) {
logger.error("The modifiers of the " + function.qualifiedName?.asString() + "() must have static!")
}
function.annotations.forEach { annotation ->
val serviceProviderItem = ServiceProviderItem(true)
serviceProviderItem.methodName = function.simpleName.asString()
serviceProviderItem.className =
function.parentDeclaration?.qualifiedName?.asString() ?: function.packageName.asString()
annotation.arguments.forEach { arg ->
when (arg.name?.asString()) {
"returnType" -> {
if (arg.value is KSType) {
serviceProviderItem.returnType =
"${(arg.value as KSType).declaration.qualifiedName?.asString()}"
if (serviceProviderItem.returnType == ServiceProvider::class.java.name) {
serviceProviderItem.returnType =
function.returnType?.resolve()?.declaration?.qualifiedName?.asString()
?: ""
}
}
}
"params" -> {
val params = ArrayList()
for (kv in arg.value as List<*>) {
if (kv is KSType) {
params.add(
transformNumber(
kv.declaration.qualifiedName?.asString() ?: ""
)
)
}
}
if (params.size == 0) {
function.parameters.forEach {
params.add(
transformNumber(
it.type.resolve().declaration.qualifiedName?.asString()
?: ""
)
)
}
} else if (params.size != function.parameters.size) {
val log = StringBuilder(function.qualifiedName?.asString())
.append("() parameter list required (")
function.parameters.forEach {
log.append(it.type.resolve().declaration.qualifiedName?.asString())
.append(",")
}
log.append("), But the declared parameter is")
repeat(params.size) {
log.append("$it,")
}
log.append(")")
logger.error(log.toString())
}
serviceProviderItem.params = params
}
}
}
list.add(serviceProviderItem)
}
}
}
private fun parseFlowTask(resolver: Resolver): ArrayList {
val list = ArrayList()
resolver.getSymbolsWithAnnotation(FlowTask::class.java.name).forEach {
it.containingFile?.let { file ->
serviceProviderDependencies.add(file)
}
it.accept(FlowTaskVisitor(list), Unit)
}
return list
}
inner class FlowTaskVisitor(private val list: ArrayList) :
TheRouterVisitor(logger) {
override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
super.visitFunctionDeclaration(function, data)
sourcePath = getSourcePath(function)
if (function.functionKind != FunctionKind.STATIC && function.functionKind != FunctionKind.TOP_LEVEL) {
logger.error("The modifiers of the " + function.qualifiedName?.asString() + "() must have static!")
}
val type = function.returnType?.resolve()?.declaration?.qualifiedName?.asString() ?: ""
if (type != Unit.javaClass.name) {
logger.error("The return type of the " + function.qualifiedName?.asString() + "() must be void")
}
if (function.parameters.size != 1) {
logger.error("=========================\n\n\n\n" + function.qualifiedName?.asString() + "() must only has Context parameter")
}
function.parameters.forEach {
if (it.type.resolve().declaration.qualifiedName?.asString() != "android.content.Context") {
logger.error(
"=========================\n\n\n\n" + function.qualifiedName?.asString() + "(" + it.type.resolve().declaration.qualifiedName?.asString() + ") must only has Context parameter"
)
}
}
function.annotations.forEach { annotation ->
val flowTaskItem = FlowTaskItem()
flowTaskItem.methodName = function.simpleName.asString()
flowTaskItem.className = function.parentDeclaration?.qualifiedName?.asString() ?: function.packageName.asString()
annotation.arguments.forEach { arg ->
when (arg.name?.asString()) {
"taskName" -> flowTaskItem.taskName = "${arg.value}"
"async" -> flowTaskItem.async = "${arg.value}".toBoolean()
"dependsOn" -> flowTaskItem.dependencies = "${arg.value}"
}
}
list.add(flowTaskItem)
}
}
}
private fun parseActionInterceptor(resolver: Resolver): ArrayList {
val list = ArrayList()
resolver.getSymbolsWithAnnotation(ActionInterceptor::class.java.name).forEach {
it.containingFile?.let { file ->
serviceProviderDependencies.add(file)
}
it.accept(ActionInterceptorVisitor(list), Unit)
}
return list
}
inner class ActionInterceptorVisitor(private val list: ArrayList) :
TheRouterVisitor(logger) {
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
super.visitClassDeclaration(classDeclaration, data)
sourcePath = getSourcePath(classDeclaration)
classDeclaration.annotations.forEach { annotation ->
val item = ActionInterceptorItem()
item.className = classDeclaration.qualifiedName?.asString().toString()
annotation.arguments.forEach { arg ->
when (arg.name?.asString()) {
"actionName" -> item.actionName = "${arg.value}"
}
}
list.add(item)
}
}
}
private fun genServiceProviderFile(
pageList: ArrayList,
flowTaskList: ArrayList,
actionInterceptorList: ArrayList
) {
if (pageList.isEmpty() && flowTaskList.isEmpty() && actionInterceptorList.isEmpty()) {
return
}
val stringBuilder = StringBuilder()
stringBuilder.append("{")
var isFirst = true
flowTaskList.sort()
pageList.sort()
actionInterceptorList.sort()
flowTaskList.forEach {
if (!isFirst) {
stringBuilder.append(",")
}
stringBuilder.append("\\\"").append(it.taskName).append("\\\":\\\"")
.append(it.dependencies).append("\\\"")
isFirst = false
}
stringBuilder.append("}")
// 确保只要编译的软硬件环境不变,类名就不会改变
val className = PREFIX_SERVICE_PROVIDER + kotlin.math.abs(
if (sourcePath.isEmpty()) {
if (pageList.isNotEmpty()) {
pageList[0].className.hashCode()
} else {
flowTaskList[0].className.hashCode()
}
} else {
sourcePath.hashCode()
}
)
var ps: PrintStream? = null
try {
val dependencies = Dependencies(aggregating = true, *serviceProviderDependencies.toTypedArray())
ps = PrintStream(codeGenerator.createNewFile(dependencies, PACKAGE, className))
ps.println("@file:JvmName(\"$className\")")
ps.println(String.format("package %s", PACKAGE))
ps.println()
ps.println("/**")
ps.println(" * Generated code, Don't modify!!!")
ps.println(" * Created by kymjs, and KSP Version is ${BuildConfig.VERSION}.")
ps.println(" * JDK Version is ${System.getProperty("java.version")}.")
ps.println(" */")
ps.println("@androidx.annotation.Keep")
ps.println(
String.format(
"public class %s : com.therouter.inject.Interceptor {",
className
)
)
ps.println()
ps.println("\toverride fun interception(clazz: Class?, vararg params: Any?): T? {")
ps.println("\t\tvar obj: T? = null")
ps.print("\t\t")
val prop = Properties()
try {
val gradleProperties = FileInputStream(PROPERTY_FILE)
prop.load(gradleProperties)
} catch (e: Exception) {
}
for (serviceProviderItem in pageList) {
//处理 USE_EXTEND 开关
if (STR_TRUE.equals(prop.getProperty(KEY_USE_EXTEND), ignoreCase = true)) {
ps.print(
String.format(
"if (%s::class.javaObjectType.isAssignableFrom(clazz)",
serviceProviderItem.returnType
)
)
} else {
ps.print(
String.format(
"if (%s::class.java.equals(clazz)",
serviceProviderItem.returnType
)
)
}
// 多参数判断
ps.print(" && params.size == ")
if (serviceProviderItem.params.size == 1) {
if (serviceProviderItem.params[0].trim { it <= ' ' }.isEmpty()) {
ps.print(0)
} else {
ps.print(1)
}
} else {
ps.print(serviceProviderItem.params.size)
}
//参数类型判断
for (count in serviceProviderItem.params.indices) {
if (!serviceProviderItem.params[count].trim { it <= ' ' }.isEmpty()) {
ps.print(
String.format(
Locale.getDefault(),
"\n\t\t\t\t&& params[%d] is %s",
count,
serviceProviderItem.params[count]
)
)
}
}
ps.println(") {")
if (serviceProviderItem.isMethod) {
ps.print(
String.format(
"\t\t\tval returnType: %s = %s.%s(",
serviceProviderItem.returnType,
serviceProviderItem.className,
serviceProviderItem.methodName
)
)
} else {
ps.print(
String.format(
"\t\t\tval returnType: %s = %s(",
serviceProviderItem.returnType,
serviceProviderItem.className
)
)
}
for (count in serviceProviderItem.params.indices) {
if (!serviceProviderItem.params[count].trim { it <= ' ' }.isEmpty()) {
//参数强转
ps.print(
String.format(
Locale.getDefault(),
"params[%d] as %s",
count,
serviceProviderItem.params[count]
)
)
if (count != serviceProviderItem.params.size - 1) {
ps.print(", ")
}
}
}
ps.println(")")
ps.println("\t\t\tobj = returnType as T?")
ps.print("\t\t} else ")
}
ps.println("{\n")
ps.println(" }")
ps.println(" return obj")
ps.println(" }")
ps.println()
ps.println("\tcompanion object { ")
ps.println()
ps.println("\tconst val TAG = \"Created by kymjs, and KSP Version is ${BuildConfig.VERSION}.\"")
ps.println("\tconst val THEROUTER_APT_VERSION = \"${BuildConfig.VERSION}\"")
ps.println("\tconst val FLOW_TASK_JSON = \"${stringBuilder}\"")
ps.println()
ps.println("\t\[email protected]")
ps.println("\t\tfun addFlowTask(context: android.content.Context, digraph: com.therouter.flow.Digraph) {")
for (item in flowTaskList) {
ps.println("\t\t\tdigraph.addTask(com.therouter.flow.Task(${item.async}, \"${item.taskName}\", \"${item.dependencies}\", object : com.therouter.flow.FlowTaskRunnable {")
ps.println("\t\t\t\toverride fun run() = ${item.className}.${item.methodName}(context)")
ps.println()
ps.println("\t\t\t\toverride fun log() = \"${item.className}.${item.methodName}(context)\"")
ps.println("\t\t\t}))")
}
for (item in actionInterceptorList) {
ps.println("\t\t\tcom.therouter.TheRouter.addActionInterceptor(\"${item.actionName}\", ${item.className}());")
}
ps.println("\t\t}")
ps.println("\t}")
ps.println("}")
ps.flush()
} finally {
ps?.close()
}
}
}
fun transformNumber(type: String): String {
return when (type) {
"byte" -> "kotlin.Byte"
"short" -> "kotlin.Short"
"int" -> "kotlin.Integer"
"long" -> "kotlin.Long"
"float" -> "kotlin.Float"
"double" -> "kotlin.Double"
"boolean" -> "kotlin.Boolean"
"char" -> "kotlin.Character"
"String" -> "kotlin.String"
"java.lang.String" -> "kotlin.String"
else -> type
}
}
fun getSourcePath(ks: KSDeclaration): String {
val pkgPath = ks.packageName.asString().replace(".", "/")
val filePath = ks.containingFile?.filePath
var sourcePath = filePath?.replace("/$pkgPath", "") ?: ""
val endIndex = sourcePath.indexOfLast { it == '/' }
if (endIndex > 0) {
sourcePath = sourcePath.substring(0, endIndex)
}
return sourcePath
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy