-
Notifications
You must be signed in to change notification settings - Fork 108
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
Generate code to have an API that provides module level metadata of Showkase elements #392
Draft
vinaygaba
wants to merge
6
commits into
master
Choose a base branch
from
vinay-module-level-metadata
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 4 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
1dbf112
Generate code to have an API that provides module level metadata of S…
vinaygaba 67254d9
Rename file name
vinaygaba db922c4
Fix detekt issue
vinaygaba dd3df4e
Generate class instead of object to avoid failing tests
vinaygaba 75edf88
Update tests
vinaygaba ea932d8
Merge branch 'master' of github.com:airbnb/Showkase into vinay-module…
vinaygaba File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
113 changes: 113 additions & 0 deletions
113
...sor/src/main/java/com/airbnb/android/showkase/processor/writer/ShowkaseModuleApiWriter.kt
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package com.airbnb.android.showkase.processor.writer | ||
|
||
import androidx.room.compiler.processing.XFiler | ||
import androidx.room.compiler.processing.XProcessingEnv | ||
import androidx.room.compiler.processing.addOriginatingElement | ||
import androidx.room.compiler.processing.writeTo | ||
import com.airbnb.android.showkase.processor.writer.ShowkaseBrowserWriter.Companion.SHOWKASE_PROVIDER_CLASS_NAME | ||
import com.airbnb.android.showkase.processor.writer.ShowkaseBrowserWriter.Companion.initializeColorCodeBlock | ||
import com.airbnb.android.showkase.processor.writer.ShowkaseBrowserWriter.Companion.initializeComponentCodeBlock | ||
import com.airbnb.android.showkase.processor.writer.ShowkaseBrowserWriter.Companion.initializeTypographyCodeBlock | ||
import com.squareup.kotlinpoet.ClassName | ||
import com.squareup.kotlinpoet.CodeBlock | ||
import com.squareup.kotlinpoet.FunSpec | ||
import com.squareup.kotlinpoet.LIST | ||
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy | ||
|
||
object ShowkaseModuleApiWriter { | ||
@Suppress("LongMethod", "LongParameterList") | ||
internal fun generateModuleLevelShowkaseProvider( | ||
environment: XProcessingEnv, | ||
moduleShowkaseBrowserProperties: ShowkaseBrowserProperties, | ||
) { | ||
if (moduleShowkaseBrowserProperties.isEmpty()) return | ||
val packageName = moduleShowkaseBrowserProperties.getPackageName() | ||
val showkaseComponentsListClassName = | ||
"${MODULE_LEVEL_SHOWKASE_PROVIDER_CLASS_PREFIX}_${packageName.normalizePackageName()}" | ||
val fileBuilder = getFileBuilder(packageName, showkaseComponentsListClassName) | ||
val componentCodeBlock = initializeComponentCodeBlock( | ||
moduleShowkaseBrowserProperties.componentsWithoutPreviewParameters, | ||
moduleShowkaseBrowserProperties.componentsWithPreviewParameters | ||
) | ||
val colorCodeBlock = initializeColorCodeBlock(moduleShowkaseBrowserProperties.colors) | ||
val typographyCodeBlock = | ||
initializeTypographyCodeBlock(moduleShowkaseBrowserProperties.typography) | ||
writeFile( | ||
environment, | ||
fileBuilder, | ||
ShowkaseBrowserWriter.SHOWKASE_PROVIDER_CLASS_NAME, | ||
showkaseComponentsListClassName, | ||
moduleShowkaseBrowserProperties, | ||
getShowkaseProviderInterfaceFunction( | ||
methodName = ShowkaseBrowserWriter.COMPONENT_INTERFACE_METHOD_NAME, | ||
returnType = LIST.parameterizedBy(ShowkaseBrowserWriter.SHOWKASE_BROWSER_COMPONENT_CLASS_NAME), | ||
codeBlock = componentCodeBlock | ||
), | ||
getShowkaseProviderInterfaceFunction( | ||
methodName = ShowkaseBrowserWriter.COLOR_INTERFACE_METHOD_NAME, | ||
returnType = LIST.parameterizedBy(ShowkaseBrowserWriter.SHOWKASE_BROWSER_COLOR_CLASS_NAME), | ||
codeBlock = colorCodeBlock | ||
), | ||
getShowkaseProviderInterfaceFunction( | ||
methodName = ShowkaseBrowserWriter.TYPOGRAPHY_INTERFACE_METHOD_NAME, | ||
returnType = LIST.parameterizedBy(ShowkaseBrowserWriter.SHOWKASE_BROWSER_TYPOGRAPHY_CLASS_NAME), | ||
codeBlock = typographyCodeBlock | ||
), | ||
showkaseRootCodegenAnnotation = null | ||
) | ||
} | ||
|
||
internal fun generateModuleMetadataPublicApi( | ||
environment: XProcessingEnv, | ||
moduleShowkaseBrowserProperties: ShowkaseBrowserProperties, | ||
) { | ||
if (moduleShowkaseBrowserProperties.isEmpty()) return | ||
val packageName = moduleShowkaseBrowserProperties.getPackageName() | ||
val normalizedPackageName = packageName.normalizePackageName() | ||
val showkaseComponentsListClassName = | ||
"${MODULE_LEVEL_SHOWKASE_PROVIDER_CLASS_PREFIX}ExtensionFunctions_${normalizedPackageName}" | ||
val fileBuilder = getFileBuilder(packageName, showkaseComponentsListClassName) | ||
|
||
fileBuilder | ||
.addFileComment("This is an auto-generated file. Please do not edit/modify this file.") | ||
.addFunction( | ||
FunSpec.builder(MODULE_METADATA_FUNCTION_NAME).apply { | ||
receiver(ShowkaseExtensionFunctionsWriter.SHOWKASE_OBJECT_CLASS_NAME) | ||
returns(ShowkaseExtensionFunctionsWriter.SHOWKASE_ELEMENTS_METADATA_CLASS_NAME) | ||
addKdoc( | ||
"Helper function that gives you access to Showkase elements that are " + | ||
"declared in a given module. This contains data about the composables, " + | ||
"colors and typography that are meant to be rendered inside the Showkase " + | ||
"browser. This is different from the " + | ||
"Showkase.${ShowkaseExtensionFunctionsWriter.METADATA_FUNCTION_NAME}() " + | ||
"function, which contains all the Showkase elements in a given " + | ||
"ShowkaseRoot graph, whereas this function only contains metadata " + | ||
"about the module it's generated in. Each module where Showkase is " + | ||
"setup will have this function generated in it." | ||
) | ||
addCode( | ||
CodeBlock.Builder() | ||
.indent() | ||
.addStatement( | ||
"return (%T() as %T).metadata()", | ||
ClassName( | ||
packageName, | ||
"${MODULE_LEVEL_SHOWKASE_PROVIDER_CLASS_PREFIX}_${normalizedPackageName}" | ||
), | ||
SHOWKASE_PROVIDER_CLASS_NAME | ||
) | ||
.unindent() | ||
.build() | ||
) | ||
moduleShowkaseBrowserProperties.zip() | ||
.forEach { addOriginatingElement(it.element) } | ||
} | ||
.build() | ||
) | ||
.build() | ||
.writeTo(environment.filer, mode = XFiler.Mode.Aggregating) | ||
} | ||
|
||
private const val MODULE_METADATA_FUNCTION_NAME = "getModuleMetadata" | ||
private const val MODULE_LEVEL_SHOWKASE_PROVIDER_CLASS_PREFIX = "ShowkaseModuleMetadata" | ||
} |
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
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
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elihart One of the challenges is which package to generate this API in. In the existing metadata APIs, we generate them in the package of the ~@ShowkaseRoot` module. As this file is generated in every module, I'm currently generating it in the package of the first element from this list. I don't quite like that. A fixed package isn't an option either since the API is identical in each module. Do you have any alternate suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean, "which package"?
It's hard for me to reason through what the new API looks like without examples in the PR summary or in the code - could you add something to show what the current output looks like?
What's your current strategy for how the test source codegen would know where to find the components for that module?
I think you may need to use an annotation to indicate the package. This could either be a new annotation (like @ShowkaseModule) or possibly you could reuse @ShowkaseRoot with the new expectation that it can be used in multiple modules.
Another option that comes to mind is that you could find the parent package common to all components in the module being processed. For example; com.example.a.b.foo and com.example.a.c.foo are processed and you identify com.example.a as the common package to generate the code in. The downside to this is it makes the output location a bit unpredictable, and prone to changing unexpectedly, so I think you probably need to use a fixed annotation.
For Airbnb, we could avoid manually adding that annotation, and only add it at CI time in each ui module before running code gen (and a similar process to also add the necessary annotation in the test sources for the test codegen)