mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-10-30 19:50:31 +00:00 
			
		
		
		
	start add variations generator
This commit is contained in:
		| @@ -1,11 +1,13 @@ | ||||
| package dev.inmo.micro_ksp.generator | ||||
|  | ||||
| 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.squareup.kotlinpoet.FileSpec | ||||
| import java.io.File | ||||
|  | ||||
| fun KSClassDeclaration.writeFile( | ||||
| fun KSDeclaration.writeFile( | ||||
|     prefix: String = "", | ||||
|     suffix: String = "", | ||||
|     relatedPath: String = "", | ||||
| @@ -21,8 +23,9 @@ fun KSClassDeclaration.writeFile( | ||||
|         "$prefix${simpleName.asString()}$suffix.kt" | ||||
|     ).takeIf { force || !it.exists() } ?.apply { | ||||
|         parentFile.mkdirs() | ||||
|         val fileSpec = fileSpecBuilder() | ||||
|         writer().use { writer -> | ||||
|             fileSpecBuilder().writeTo(writer) | ||||
|             fileSpec.writeTo(writer) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -42,8 +45,9 @@ fun KSFile.writeFile( | ||||
|         "$prefix${fileName.dropLastWhile { it != '.' }.removeSuffix(".")}$suffix.kt" | ||||
|     ).takeIf { force || !it.exists() } ?.apply { | ||||
|         parentFile.mkdirs() | ||||
|         val fileSpec = fileSpecBuilder() | ||||
|         writer().use { writer -> | ||||
|             fileSpecBuilder().writeTo(writer) | ||||
|             fileSpec.writeTo(writer) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
|   | ||||
							
								
								
									
										7
									
								
								ksp/variations/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								ksp/variations/build.gradle
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| plugins { | ||||
|     id "org.jetbrains.kotlin.multiplatform" | ||||
|     id "org.jetbrains.kotlin.plugin.serialization" | ||||
|     id "com.android.library" | ||||
| } | ||||
|  | ||||
| apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project" | ||||
							
								
								
									
										21
									
								
								ksp/variations/generator/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								ksp/variations/generator/build.gradle
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| plugins { | ||||
|     id "org.jetbrains.kotlin.jvm" | ||||
| } | ||||
|  | ||||
| apply from: "$publish_jvm" | ||||
|  | ||||
| repositories { | ||||
|     mavenCentral() | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
|     api project(":micro_utils.ksp.generator") | ||||
|     api project(":micro_utils.ksp.variations") | ||||
|     api libs.kotlin.poet | ||||
|     api libs.ksp | ||||
| } | ||||
|  | ||||
| java { | ||||
|     sourceCompatibility = JavaVersion.VERSION_17 | ||||
|     targetCompatibility = JavaVersion.VERSION_17 | ||||
| } | ||||
							
								
								
									
										148
									
								
								ksp/variations/generator/src/main/kotlin/Processor.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								ksp/variations/generator/src/main/kotlin/Processor.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | ||||
| package dev.inmo.micro_utils.ksp.variations.generator | ||||
|  | ||||
| import com.google.devtools.ksp.KspExperimental | ||||
| import com.google.devtools.ksp.getAnnotationsByType | ||||
| import com.google.devtools.ksp.processing.CodeGenerator | ||||
| import com.google.devtools.ksp.processing.Resolver | ||||
| import com.google.devtools.ksp.processing.SymbolProcessor | ||||
| import com.google.devtools.ksp.symbol.* | ||||
| import com.squareup.kotlinpoet.* | ||||
| import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy | ||||
| import com.squareup.kotlinpoet.ksp.toClassName | ||||
| import com.squareup.kotlinpoet.ksp.toKModifier | ||||
| import com.squareup.kotlinpoet.ksp.toTypeName | ||||
| import dev.inmo.micro_ksp.generator.companion | ||||
| import dev.inmo.micro_ksp.generator.findSubClasses | ||||
| import dev.inmo.micro_ksp.generator.writeFile | ||||
| import dev.inmo.micro_utils.ksp.variations.GenerateVariations | ||||
| import dev.inmo.micro_utils.ksp.variations.GenerationVariant | ||||
|  | ||||
| class Processor( | ||||
|     private val codeGenerator: CodeGenerator | ||||
| ) : SymbolProcessor { | ||||
|     private fun KSClassDeclaration.findSealedConnection(potentialSealedParent: KSClassDeclaration): Boolean { | ||||
|         val targetClassname = potentialSealedParent.qualifiedName ?.asString() | ||||
|         return superTypes.any { | ||||
|             val itAsDeclaration = it.resolve().declaration as? KSClassDeclaration ?: return@any false | ||||
|             targetClassname == (itAsDeclaration.qualifiedName ?.asString()) || (itAsDeclaration.getSealedSubclasses().any() && itAsDeclaration.findSealedConnection(potentialSealedParent)) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun KSClassDeclaration.resolveSubclasses( | ||||
|         searchIn: Sequence<KSAnnotated>, | ||||
|         allowNonSealed: Boolean | ||||
|     ): Sequence<KSClassDeclaration> { | ||||
|         return findSubClasses(searchIn).let { | ||||
|             if (allowNonSealed) { | ||||
|                 it | ||||
|             } else { | ||||
|                 it.filter { | ||||
|                     it.findSealedConnection(this) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @OptIn(KspExperimental::class) | ||||
|     private fun FileSpec.Builder.generateVariations( | ||||
|         ksFunctionDeclaration: KSFunctionDeclaration, | ||||
|         resolver: Resolver | ||||
|     ) { | ||||
|         val annotation = ksFunctionDeclaration.getAnnotationsByType(GenerateVariations::class).first() | ||||
|         val variations: List<Pair<List<GenerationVariant>, KSValueParameter>> = ksFunctionDeclaration.parameters.mapNotNull { | ||||
|             val variationAnnotations = it.getAnnotationsByType(GenerationVariant::class).toList().ifEmpty { return@mapNotNull null } | ||||
|             variationAnnotations to it | ||||
|         } | ||||
|         val accumulatedGenerations = mutableSetOf<FunSpec>() | ||||
|         variations.forEach { (variations, parameter) -> | ||||
|             if (accumulatedGenerations.isEmpty()) { | ||||
|                 variations.forEach { variation -> | ||||
|                     accumulatedGenerations.add( | ||||
|                         FunSpec.builder(ksFunctionDeclaration.simpleName.asString()).apply { | ||||
|                             modifiers.addAll(ksFunctionDeclaration.modifiers.mapNotNull { it.toKModifier() }) | ||||
|                             ksFunctionDeclaration.parameters.forEach { | ||||
|                                 parameters.add( | ||||
|                                     (if (it == parameter) { | ||||
|                                         ParameterSpec | ||||
|                                             .builder( | ||||
|                                                 variation.argName, | ||||
|                                                 if (variation.varargTypes.isEmpty()) { | ||||
|                                                     variation.type.asTypeName() | ||||
|                                                 } else { | ||||
|                                                     variation.type.parameterizedBy(*variation.varargTypes) | ||||
|                                                 } | ||||
|                                             ) | ||||
|                                             .apply { | ||||
|                                                 val name = it.name ?.asString() ?: "this" | ||||
|                                                 if (it.isVararg) { | ||||
|                                                     defaultValue( | ||||
|                                                         """ | ||||
|                                                             *$name.map { it.${variation.conversion} }.toTypedArray() | ||||
|                                                         """.trimIndent() | ||||
|                                                     ) | ||||
|                                                 } else { | ||||
|                                                     defaultValue("$name.${variation.conversion}") | ||||
|                                                 } | ||||
|                                             } | ||||
|                                     } else { | ||||
|                                         ParameterSpec | ||||
|                                             .builder( | ||||
|                                                 it.name ?.asString() ?: return@forEach, | ||||
|                                                 it.type.toTypeName(), | ||||
|                                             ) | ||||
|                                     }) | ||||
|                                         .apply { | ||||
|                                             if (it.isCrossInline) { | ||||
|                                                 addModifiers(KModifier.CROSSINLINE) | ||||
|                                             } | ||||
|                                             if (it.isVal) { | ||||
|                                                 addModifiers(KModifier.VALUE) | ||||
|                                             } | ||||
|                                             if (it.isNoInline) { | ||||
|                                                 addModifiers(KModifier.NOINLINE) | ||||
|                                             } | ||||
|                                             if (it.isVararg) { | ||||
|                                                 addModifiers(KModifier.VARARG) | ||||
|                                             } | ||||
|                                         } | ||||
|                                         .build() | ||||
|                                 ) | ||||
|                             } | ||||
|                         }.build() | ||||
|                     ) | ||||
|                 } | ||||
|             } else { | ||||
|  | ||||
|             } | ||||
|         } | ||||
|         accumulatedGenerations.forEach { | ||||
|             addFunction(it) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @OptIn(KspExperimental::class) | ||||
|     override fun process(resolver: Resolver): List<KSAnnotated> { | ||||
|         (resolver.getSymbolsWithAnnotation(GenerateVariations::class.qualifiedName!!)).filterIsInstance<KSFunctionDeclaration>().forEach { | ||||
|             val prefix = (it.getAnnotationsByType(GenerateVariations::class)).firstOrNull() ?.prefix ?.takeIf { | ||||
|                 it.isNotEmpty() | ||||
|             } ?: it.simpleName.asString().replaceFirst(it.simpleName.asString(), "") | ||||
|             it.writeFile(prefix = prefix, suffix = "GeneratedVariation") { | ||||
|                 FileSpec.builder( | ||||
|                     it.packageName.asString(), | ||||
|                     "${it.simpleName.getShortName()}GeneratedVariation" | ||||
|                 ).apply { | ||||
|                     addFileComment( | ||||
|                         """ | ||||
|                         THIS CODE HAVE BEEN GENERATED AUTOMATICALLY | ||||
|                         TO REGENERATE IT JUST DELETE FILE | ||||
|                         ORIGINAL FILE: ${it.containingFile ?.fileName} | ||||
|                         """.trimIndent() | ||||
|                     ) | ||||
|                     generateVariations(it, resolver) | ||||
|                 }.build() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return emptyList() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								ksp/variations/generator/src/main/kotlin/Provider.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								ksp/variations/generator/src/main/kotlin/Provider.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| package dev.inmo.micro_utils.ksp.variations.generator | ||||
|  | ||||
| import com.google.devtools.ksp.processing.SymbolProcessor | ||||
| import com.google.devtools.ksp.processing.SymbolProcessorEnvironment | ||||
| import com.google.devtools.ksp.processing.SymbolProcessorProvider | ||||
|  | ||||
| class Provider : SymbolProcessorProvider { | ||||
|     override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = Processor( | ||||
|         environment.codeGenerator | ||||
|     ) | ||||
| } | ||||
| @@ -0,0 +1 @@ | ||||
| dev.inmo.micro_utils.ksp.variations.generator.Provider | ||||
							
								
								
									
										27
									
								
								ksp/variations/generator/test/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								ksp/variations/generator/test/build.gradle
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| plugins { | ||||
|     id "org.jetbrains.kotlin.multiplatform" | ||||
|     id "org.jetbrains.kotlin.plugin.serialization" | ||||
|     id "com.android.library" | ||||
|     id "com.google.devtools.ksp" | ||||
| } | ||||
|  | ||||
| apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project" | ||||
|  | ||||
|  | ||||
| kotlin { | ||||
|     sourceSets { | ||||
|         commonMain { | ||||
|             dependencies { | ||||
|                 api project(":micro_utils.ksp.variations") | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| dependencies { | ||||
|     add("kspCommonMainMetadata", project(":micro_utils.ksp.variations.generator")) | ||||
| } | ||||
|  | ||||
| ksp { | ||||
| } | ||||
| @@ -0,0 +1,16 @@ | ||||
| import dev.inmo.micro_utils.ksp.variations.GenerateVariations | ||||
| import dev.inmo.micro_utils.ksp.variations.GenerationVariant | ||||
|  | ||||
| data class Sample( | ||||
|     val value: String | ||||
| ) | ||||
|  | ||||
| @GenerateVariations | ||||
| fun sample( | ||||
|     @GenerationVariant( | ||||
|         "example", | ||||
|         Sample::class, | ||||
|         "value" | ||||
|     ) | ||||
|     example: String = "12" | ||||
| ) = println(example) | ||||
| @@ -0,0 +1,7 @@ | ||||
| package dev.inmo.micro_utils.ksp.variations | ||||
|  | ||||
| @Retention(AnnotationRetention.BINARY) | ||||
| @Target(AnnotationTarget.FUNCTION) | ||||
| annotation class GenerateVariations( | ||||
|     val prefix: String = "" | ||||
| ) | ||||
							
								
								
									
										13
									
								
								ksp/variations/src/commonMain/kotlin/GenerationVariant.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								ksp/variations/src/commonMain/kotlin/GenerationVariant.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| package dev.inmo.micro_utils.ksp.variations | ||||
|  | ||||
| import kotlin.reflect.KClass | ||||
|  | ||||
| @Retention(AnnotationRetention.BINARY) | ||||
| @Repeatable | ||||
| @Target(AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.VALUE_PARAMETER) | ||||
| annotation class GenerationVariant( | ||||
|     val argName: String, | ||||
|     val type: KClass<*>, | ||||
|     val conversion: String, | ||||
|     vararg val varargTypes: KClass<*> | ||||
| ) | ||||
| @@ -62,6 +62,10 @@ String[] includes = [ | ||||
|     ":ksp:classcasts:generator", | ||||
|     ":ksp:classcasts:generator:test", | ||||
|  | ||||
|     ":ksp:variations", | ||||
|     ":ksp:variations:generator", | ||||
|     ":ksp:variations:generator:test", | ||||
|  | ||||
|     ":dokka" | ||||
| ] | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user