All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.autonomousapps.model.internal.KtFile.kt Maven / Gradle / Ivy

There is a newer version: 2.6.1
Show newest version
// Copyright (c) 2024. Tony Robalik.
// SPDX-License-Identifier: Apache-2.0
package com.autonomousapps.model.internal

import com.squareup.moshi.JsonClass
import kotlinx.metadata.jvm.KotlinModuleMetadata
import kotlinx.metadata.jvm.UnstableMetadataApi
import java.io.File
import java.io.InputStream
import java.util.zip.ZipFile

/**
 * A "KT File" is one that has top-level declarations, and so the class file is something like
 * `com.example.ThingKt`, but imports in Kotlin code look like `com.example.CONSTANT` (rather than
 * `com.example.ThingKt.CONSTANT`).
 */
@JsonClass(generateAdapter = false)
internal data class KtFile(
  val fqcn: String,
  val name: String
) : Comparable {

  override fun compareTo(other: KtFile): Int {
    return compareBy(KtFile::fqcn)
      .thenComparing(compareBy(KtFile::name))
      .compare(this, other)
  }

  internal companion object {
    private const val KOTLIN_MODULE = ".kotlin_module"

    fun fromDirectory(dir: File): Set {
      check(dir.isDirectory) { "Expected directory. Was '${dir.absolutePath}'" }

      return dir
        .walkBottomUp()
        .firstOrNull { it.name.endsWith(KOTLIN_MODULE) }
        ?.let { fromFile(it) }
        .orEmpty()
    }

    fun fromZip(zipFile: ZipFile): Set {
      return zipFile.entries()
        .toList()
        .find { it.name.endsWith(KOTLIN_MODULE) }
        ?.let { fromInputStream(zipFile.getInputStream(it)) }
        .orEmpty()
    }

    private fun fromFile(file: File): Set = fromInputStream(file.inputStream())

    @OptIn(UnstableMetadataApi::class)
    private fun fromInputStream(input: InputStream): Set {
      val bytes = input.use { it.readBytes() }
      val metadata = KotlinModuleMetadata.read(bytes)
      val module = metadata.kmModule

      return module.packageParts.flatMap { (packageName, parts) ->
        parts.fileFacades.map { facade ->
          // com/example/library/ConstantsKt --> [com.example.library.ConstantsKt, ConstantsKt]
          val fqcn = facade.replace('/', '.')
          KtFile(fqcn, fqcn.removePrefix("$packageName."))
        }
      }.toSortedSet()
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy