Last active
August 1, 2022 06:14
-
-
Save DjakaTechnology/84620de7c7f6d908849afc4f0afc63f9 to your computer and use it in GitHub Desktop.
This will migrate file from gson or regular POJO to moshi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env kotlin | |
import java.io.File | |
import java.nio.file.Files | |
import java.nio.file.Path | |
import java.nio.file.Paths | |
/** | |
* How to use: | |
* Run script | |
* Follow the instruction | |
* */ | |
enum class MigrationType(val id: Int, val message: String) { | |
ONLY_WITHOUT_MOSHI(1, "Migrate files that doesn't contain moshi import"), | |
ONLY_GSON_IMPORT(2, "Migrate files that contain gson import"), | |
ALL_FILE(3, "Migrate all files"), | |
} | |
enum class ResultType(val id: Int, val message: String) { | |
OUTPUT_SUBFOLDER(1, """Create a new file inside "output/" subfolder"""), | |
DIRECT(2, "Write file directly") | |
} | |
enum class FileExtension(val id: Int, val message: String) { | |
KOTLIN(1, "Only migrate kotlin files"), | |
JAVA(2, "Only migrate Java files"), | |
ALL(3, "Migrate both Kotlin and Java") | |
} | |
println( | |
""" | |
================= | |
Specify target path. | |
- Path can be relative path from this file | |
- Path can be absoulte path | |
================= | |
""".trimIndent() | |
) | |
val targetPath = readLine() ?: throw IllegalStateException("Input folder cannot be null") | |
println( | |
""" | |
================= | |
Select migrating type: | |
${MigrationType.values().joinToString("\n") { "${it.id} ${it.message}" }} | |
=================""".trimIndent() | |
) | |
val migrationType = readLine()?.toInt()?.let { input -> | |
MigrationType.values().first { it.id == input } | |
} ?: throw IllegalStateException("Please choose between 1, 2 or 3") | |
println( | |
""" | |
================= | |
Select affected file extension: | |
${FileExtension.values().joinToString("\n") { "${it.id} ${it.message}" }} | |
=================""".trimIndent() | |
) | |
val fileExtensionType = readLine()?.toInt()?.let { input -> | |
FileExtension.values().first { it.id == input } | |
} ?: throw IllegalStateException("Please choose between 1 & 2") | |
println( | |
""" | |
================= | |
Select result type: | |
${ResultType.values().joinToString("\n") { "${it.id} ${it.message}" }} | |
=================""".trimIndent() | |
) | |
val resultType = readLine()?.toInt()?.let { input -> | |
ResultType.values().first { it.id == input } | |
} ?: throw IllegalStateException("Please choose between 1 & 2") | |
println( | |
""" | |
================= | |
Running operation with: | |
Path: ${targetPath} | |
Migration: ${migrationType.message} | |
Result: ${resultType.message} | |
================= | |
""".trimIndent() | |
) | |
println() | |
val currentPath: Path = Paths.get("").toAbsolutePath() | |
val inputPath: Path = currentPath.resolve(targetPath) | |
var isKotlinAllowed = true | |
var isJavaAllowed = true | |
when(fileExtensionType) { | |
FileExtension.KOTLIN -> { | |
isKotlinAllowed = true | |
isJavaAllowed = false | |
} | |
FileExtension.JAVA -> { | |
isKotlinAllowed = false | |
isJavaAllowed = false | |
} | |
FileExtension.ALL -> { | |
isKotlinAllowed = true | |
isJavaAllowed = true | |
} | |
} | |
Files.walk(inputPath).forEach { | |
val isKotlin = it.fileName.toString().endsWith(".kt") | |
val isJava = it.fileName.toString().endsWith(".java") | |
if ((isKotlin && isKotlinAllowed) || (isJava && isJavaAllowed)) { | |
println("Found: ${it.toAbsolutePath()}") | |
val content = it.toFile().readText() | |
val result = when (migrationType) { | |
MigrationType.ONLY_GSON_IMPORT -> if (isHadGson(content)) injectMoshi(content, isJava) else content | |
MigrationType.ONLY_WITHOUT_MOSHI -> if (isHadMoshi(content)) content else injectMoshi(content, isJava) | |
MigrationType.ALL_FILE -> injectMoshi(content, isJava) | |
} | |
when (resultType) { | |
ResultType.OUTPUT_SUBFOLDER -> { | |
val relativePath = inputPath.relativize(it) | |
if (relativePath.parent != null) { | |
File("output/${relativePath.parent}").mkdirs() | |
} else { | |
File("output").mkdirs() | |
} | |
File("output/${relativePath}").apply { | |
println("Writing to: $absolutePath") | |
writeText(result) | |
} | |
} | |
ResultType.DIRECT -> { | |
it.toFile().apply { | |
println("Writing to: $absolutePath") | |
writeText(result) | |
} | |
} | |
} | |
} | |
} | |
fun injectMoshi( | |
content: String, | |
semiColon: Boolean = false, | |
): String { | |
val import = mutableSetOf<String>() | |
val result = mutableListOf<String>() | |
val importKey = "import " | |
val moshiJsonClass = "com.squareup.moshi.JsonClass" | |
val moshiJson = "com.squareup.moshi.Json" | |
val tempAnnotation = mutableListOf<String>() | |
content.lines().forEach { | |
when { | |
it.startsWith(importKey) -> { | |
import.add(it.substring(importKey.length)) | |
} | |
it.contains("@") -> { | |
if (isInsideComment(it)) { | |
result.add(it) | |
return@forEach | |
} | |
tempAnnotation.add(it) | |
result.add(it) | |
} | |
it.contains("fun ") -> { | |
if (isInsideComment(it)) { | |
result.add(it) | |
return@forEach | |
} | |
result.add(it) | |
tempAnnotation.clear() | |
} | |
it.contains("class ") -> { | |
if (isInsideComment(it)) { | |
result.add(it) | |
return@forEach | |
} | |
if (it.contains("enum class ")) { | |
result.add(it) | |
return@forEach | |
} | |
val jsonClassAdapterString = "@JsonClass(generateAdapter = true)" | |
if (tempAnnotation.isNotEmpty()) { | |
val isHadJsonClassAnnotation = tempAnnotation.firstOrNull { it.contains(jsonClassAdapterString) } != null | |
if (isHadJsonClassAnnotation) { | |
result.add(it) | |
tempAnnotation.clear() | |
return@forEach | |
} | |
} | |
// Add whitespace with import when needed | |
if (import.isEmpty()) { | |
result.add("") | |
} | |
import.add(moshiJsonClass) | |
val indentSize: Int = it.indexOfFirst { it.isLetter() } | |
val indent = " ".repeat(indentSize) | |
result.add("$indent$jsonClassAdapterString") | |
result.add(it) | |
} | |
it.contains("@SerializedName(") -> { | |
import.add(moshiJson) | |
val indentSize = it.indexOf("@SerializedName(") | |
val indent = " ".repeat(indentSize) | |
val fieldName = it.trim() | |
.substringAfter("@SerializedName(\"") | |
.substringBefore("\")") | |
result.add("""$indent@Json(name = "$fieldName")""") | |
result.add(it) | |
} | |
else -> { | |
result.add(it) | |
} | |
} | |
} | |
/** | |
* Reinsert import back to result | |
* | |
* index = 0 - 1 is reserved for: | |
* ============= | |
* package xxxx | |
* | |
* ============= | |
* */ | |
if (result.size != 2) { | |
val importString = import.toList().sorted().joinToString("\n") { | |
if (semiColon) { | |
"$importKey$it;" | |
} else { | |
importKey + it | |
} | |
} | |
if (importString.isNotEmpty()) { | |
result.add(2, importString) | |
} | |
} | |
return result.joinToString("\n") | |
} | |
fun isHadGson(content: String): Boolean { | |
return content.contains("com.google.gson") | |
} | |
fun isHadMoshi(content: String): Boolean { | |
return content.contains("com.squareup.moshi.") | |
} | |
fun isInsideComment(it: String) = it.startsWith("//") || it.startsWith("*") || it.startsWith(" *") || it.startsWith("/**") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment