Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify LyricistConfig and common processor things #36

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lyricist-processor-compose/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ apply from: "../kotlin-module.gradle"
dependencies {
implementation libs.ksp
implementation libs.caseFormat
api project(":lyricist-processor")
}

apply plugin: "com.vanniktech.maven.publish"
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import com.google.devtools.ksp.symbol.KSPropertyDeclaration
import com.google.devtools.ksp.symbol.KSValueArgument
import com.google.devtools.ksp.validate

internal class LyricistSymbolProcessor(
internal class LyricistComposeSymbolProcessor(
private val config: LyricistConfig,
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger
Expand Down

This file was deleted.

This file was deleted.

1 change: 1 addition & 0 deletions lyricist-processor-xml/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ dependencies {
implementation libs.ksp
implementation libs.caseFormat
implementation libs.konsumeXml
api project(":lyricist-processor")
}

apply plugin: "com.vanniktech.maven.publish"
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package cafe.adriel.lyricist.processor.xml.internal

import cafe.adriel.lyricist.processor.xml.internal.ktx.INDENTATION
import cafe.adriel.lyricist.processor.xml.internal.ktx.filterXmlStringFiles
import cafe.adriel.lyricist.processor.xml.internal.ktx.formatted
import cafe.adriel.lyricist.processor.xml.internal.ktx.getXmlStrings
import cafe.adriel.lyricist.processor.xml.internal.ktx.languageTag
import cafe.adriel.lyricist.processor.xml.internal.ktx.normalized
import cafe.adriel.lyricist.processor.xml.internal.ktx.params
package cafe.adriel.lyricist.processor.internal

import cafe.adriel.lyricist.processor.internal.xml.LanguageTag
import cafe.adriel.lyricist.processor.internal.xml.StringResource
import cafe.adriel.lyricist.processor.internal.xml.StringResources
import cafe.adriel.lyricist.processor.internal.xml.ktx.INDENTATION
import cafe.adriel.lyricist.processor.internal.xml.ktx.filterXmlStringFiles
import cafe.adriel.lyricist.processor.internal.xml.ktx.formatted
import cafe.adriel.lyricist.processor.internal.xml.ktx.getXmlStrings
import cafe.adriel.lyricist.processor.internal.xml.ktx.languageTag
import cafe.adriel.lyricist.processor.internal.xml.ktx.normalized
import cafe.adriel.lyricist.processor.internal.xml.ktx.params
import com.fleshgrinder.extensions.kotlin.toLowerCamelCase
import com.fleshgrinder.extensions.kotlin.toUpperCamelCase
import com.google.devtools.ksp.processing.CodeGenerator
Expand All @@ -18,24 +21,22 @@ import com.google.devtools.ksp.symbol.KSAnnotated
import java.io.File

internal class LyricistXmlSymbolProcessor(
private val config: LyricistXmlConfig,
private val config: LyricistConfig,
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger
) : SymbolProcessor {

private val strings = mutableMapOf<LanguageTag, StringResources>()

override fun process(resolver: Resolver): List<KSAnnotated> {
strings += File(config.resourcesPath)
strings += File(config.resourcesPathOrThrow)
.walk()
.filterXmlStringFiles()
.groupBy { file ->
val languageTag = file.languageTag

if (languageTag.isBlank()) {
languageTag.ifBlank {
config.defaultLanguageTag
} else {
languageTag
}
}
.mapValues { (_, files) ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cafe.adriel.lyricist.processor.xml.internal
package cafe.adriel.lyricist.processor.internal.xml

internal typealias StringResources = Map<ResourceName, StringResource>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cafe.adriel.lyricist.processor.xml.internal.ktx
package cafe.adriel.lyricist.processor.internal.xml.ktx

import cafe.adriel.lyricist.processor.xml.internal.LanguageTag
import cafe.adriel.lyricist.processor.xml.internal.Quantity
import cafe.adriel.lyricist.processor.internal.xml.LanguageTag
import cafe.adriel.lyricist.processor.internal.xml.Quantity
import java.io.File

internal val INDENTATION = " ".repeat(4)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package cafe.adriel.lyricist.processor.xml.internal.ktx
package cafe.adriel.lyricist.processor.internal.xml.ktx

import cafe.adriel.lyricist.processor.xml.internal.Quantity
import cafe.adriel.lyricist.processor.xml.internal.ResourceName
import cafe.adriel.lyricist.processor.xml.internal.StringResource
import cafe.adriel.lyricist.processor.internal.xml.Quantity
import cafe.adriel.lyricist.processor.internal.xml.ResourceName
import cafe.adriel.lyricist.processor.internal.xml.StringResource
import com.gitlab.mvysny.konsumexml.Konsumer
import com.gitlab.mvysny.konsumexml.konsumeXml
import java.io.File
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

1 change: 1 addition & 0 deletions lyricist-processor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
10 changes: 10 additions & 0 deletions lyricist-processor/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apply(from = "../kotlin-module.gradle")

plugins {
id("com.vanniktech.maven.publish")
}

dependencies {
add("implementation", libs.ksp)
add("compileOnly", kotlin("reflect"))
}
2 changes: 2 additions & 0 deletions lyricist-processor/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
POM_NAME=Lyricist Processor
POM_ARTIFACT_ID=lyricist-processor
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cafe.adriel.lyricist.processor.internal

public data class LyricistConfig(
val packageName: String,
val moduleName: String,
val internalVisibility: Boolean,
val defaultLanguageTag: String,
val resourcesPath: String,
val resourcesFilenameFormat: String,
val generateStringsProperty: Boolean,
)

public val LyricistConfig.resourcesPathOrThrow: String get() {
require(resourcesPath.isNotEmpty()) {
"Lyricist KSP option ${ProcessorOptions.RESOURCES_PATH} must be defined for XML and Properties processor"
}

return resourcesPath
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cafe.adriel.lyricist.processor.internal

import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.symbol.KSAnnotated

internal class LyricistSymbolProcessor(
private val processors: List<SymbolProcessor>,
) : SymbolProcessor {

override fun process(resolver: Resolver): List<KSAnnotated> {
processors.forEach { processor ->
processor.process(resolver)
}
return emptyList()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package cafe.adriel.lyricist.processor.internal

import cafe.adriel.lyricist.processor.internal.ProcessorOptions.DEFAULT_LANGUAGE_TAG
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.DEFAULT_PACKAGE_NAME
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.DEFAULT_RESOURCES_FILENAME_FORMAT
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.GENERATE_STRINGS_PROPERTY
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.INTERNAL_VISIBILITY
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.LANGUAGE_TAG
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.MODULE_NAME
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.PACKAGE_NAME
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.RESOURCES_FILENAME_FORMAT
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.RESOURCES_PATH
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.SYMBOL_PROCESSOR_PATH
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.XML_DEFAULT_LANGUAGE_TAG
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.XML_RESOURCES_PATH
import cafe.adriel.lyricist.processor.internal.ProcessorOptions.allKnownProcessors
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
import kotlin.reflect.full.primaryConstructor

internal class LyricistSymbolProcessorProvider : SymbolProcessorProvider {

override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = with(environment) {
val config = createConfig()
val processors = findProcessors(config)

LyricistSymbolProcessor(processors)
}

private fun SymbolProcessorEnvironment.createConfig() = LyricistConfig(
packageName = options.getOrDefault(PACKAGE_NAME, DEFAULT_PACKAGE_NAME),
moduleName = options[MODULE_NAME].orEmpty(),
internalVisibility = options[INTERNAL_VISIBILITY].toBoolean(),
defaultLanguageTag = getOptionAndWarnIfDeprecated(
deprecatedKey = XML_DEFAULT_LANGUAGE_TAG,
nonDeprecatedKey = LANGUAGE_TAG,
defaultValue = DEFAULT_LANGUAGE_TAG
),
resourcesPath = getOptionAndWarnIfDeprecated(
deprecatedKey = XML_RESOURCES_PATH,
nonDeprecatedKey = RESOURCES_PATH,
defaultValue = "",
),
resourcesFilenameFormat = options.getOrDefault(RESOURCES_FILENAME_FORMAT, DEFAULT_RESOURCES_FILENAME_FORMAT),
generateStringsProperty = options[GENERATE_STRINGS_PROPERTY].toBoolean(),
)

private fun SymbolProcessorEnvironment.getOptionAndWarnIfDeprecated(
deprecatedKey: String,
nonDeprecatedKey: String,
defaultValue: String,
): String {
val value = options[deprecatedKey]
if (value != null) {
logger.warn(
"Lyricist KSP argument \"$deprecatedKey\" is deprecated, " +
"use \"$nonDeprecatedKey\" instead."
)
return value
}

return options.getOrDefault(nonDeprecatedKey, defaultValue)
}

private fun SymbolProcessorEnvironment.findProcessors(config: LyricistConfig): List<SymbolProcessor> {
val foundProcessors = mutableListOf<SymbolProcessor>()
allKnownProcessors.forEach { processorName ->
val className = SYMBOL_PROCESSOR_PATH.format(processorName.replaceFirstChar(Char::uppercaseChar))
val processorClass = try {
Class.forName(className)
} catch (_: ClassNotFoundException) {
return@forEach
}

val constructor = requireNotNull(processorClass.kotlin.primaryConstructor) {
"Missing primary constructor(LyricistConfig, CodeGenerator, Logger) @ $processorClass"
}
val symbolProcessor = constructor.call(config, codeGenerator, logger) as SymbolProcessor

foundProcessors.add(symbolProcessor)
logger.info("$className loaded")
}

return foundProcessors.toList()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package cafe.adriel.lyricist.processor.internal

public object ProcessorOptions {

public const val SYMBOL_PROCESSOR_PATH: String = "cafe.adriel.lyricist.processor.internal.Lyricist%sSymbolProcessor"

// Common Options
public const val PACKAGE_NAME: String = "lyricist.packageName"
public const val MODULE_NAME: String = "lyricist.moduleName"
public const val INTERNAL_VISIBILITY: String = "lyricist.internalVisibility"
public const val LANGUAGE_TAG: String = "lyricist.defaultLanguageTag"
public const val RESOURCES_PATH: String = "lyricist.resourcesPath"
public const val RESOURCES_FILENAME_FORMAT: String = "lyricist.resourcesFilenameFormat"
public const val GENERATE_STRINGS_PROPERTY: String = "lyricist.generateStringsProperty"

public const val DEFAULT_PACKAGE_NAME: String = "cafe.adriel.lyricist"
public const val DEFAULT_LANGUAGE_TAG: String = "en"
public const val DEFAULT_RESOURCES_FILENAME_FORMAT: String = "messages_{lang}.properties"

// XML Processor options
public const val XML_RESOURCES_PATH: String = "lyricist.xml.resourcesPath"
public const val XML_DEFAULT_LANGUAGE_TAG: String = "lyricist.xml.defaultLanguageTag"

public val allKnownProcessors: List<String> = listOf("xml", "compose", "properties")
}
4 changes: 4 additions & 0 deletions sample-xml/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ dependencies {

implementation libs.compose.runtime
implementation libs.compose.ui.text
}

kotlin {
jvmToolchain(8)
}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dependencyResolutionManagement {
include(
":lyricist-compose",
":lyricist-core",
":lyricist-processor",
":lyricist-processor-compose",
":lyricist-processor-xml",
":sample",
Expand Down