fix: inline functions in templates API

This commit is contained in:
Akash Yadav
2023-11-06 00:32:27 +05:30
parent 35b7185ce1
commit 43907984e5
16 changed files with 83 additions and 68 deletions
@@ -54,7 +54,7 @@ class AndroidModuleTemplateBuilder : ModuleTemplateBuilder() {
/**
* Configure the properties for `AndroidManifest.xml` file.
*/
fun manifest(block: AndroidManifestBuilder.() -> Unit) {
inline fun manifest(crossinline block: AndroidManifestBuilder.() -> Unit) {
manifest.apply(block)
}
@@ -81,7 +81,7 @@ class AndroidModuleTemplateBuilder : ModuleTemplateBuilder() {
*
* @param configure Function to configure the resources.
*/
fun RecipeExecutor.res(configure: AndroidModuleResManager.() -> Unit) {
inline fun RecipeExecutor.res(crossinline configure: AndroidModuleResManager.() -> Unit) {
res.apply(configure)
}
@@ -97,8 +97,8 @@ class AndroidModuleTemplateBuilder : ModuleTemplateBuilder() {
*
* @param name The name of the class.
*/
fun RecipeExecutor.createActivity(name: String = "MainActivity",
configure: TypeSpec.Builder.() -> Unit
inline fun RecipeExecutor.createActivity(name: String = "MainActivity",
crossinline configure: TypeSpec.Builder.() -> Unit
) {
sources {
createClass(data.packageName, name, configure)
@@ -42,14 +42,18 @@ abstract class ModuleTemplateBuilder :
internal val platforms = hashSetOf<Dependency>()
internal val dependencies = hashSetOf<Dependency>()
protected val sourceWriter = SourceWriter()
@PublishedApi
internal val sourceWriter = SourceWriter()
@PublishedApi
internal var _name: String? = null
val name: String
get() = checkNotNull(_name) { "Name not set to module template" }
protected open fun RecipeExecutor.preConfig() {}
protected open fun RecipeExecutor.postConfig() {}
open fun RecipeExecutor.preConfig() {}
open fun RecipeExecutor.postConfig() {}
/**
* Get the asset path for base module project template.
@@ -123,7 +127,7 @@ abstract class ModuleTemplateBuilder :
*
* @param configure Function for configuring the source files.
*/
fun RecipeExecutor.sources(configure: SourceWriter.() -> Unit) {
inline fun RecipeExecutor.sources(crossinline configure: SourceWriter.() -> Unit) {
sourceWriter.apply(configure)
}
@@ -133,8 +137,8 @@ abstract class ModuleTemplateBuilder :
* @param moduleData Called after the base configuration is setup and before the [recipe] is executed. Caller can perform its own
* pre-recipe configuration here. Returns the [ModuleTemplateData] instance.
*/
fun commonPreRecipe(extraConfig: TemplateRecipeConfigurator = {},
moduleData: RecipeExecutor.() -> ModuleTemplateData
inline fun commonPreRecipe(crossinline extraConfig: TemplateRecipeConfigurator = {},
crossinline moduleData: RecipeExecutor.() -> ModuleTemplateData
): TemplateRecipeConfigurator = {
val data = moduleData()
@@ -39,10 +39,14 @@ class ProjectTemplateBuilder :
ExecutorDataTemplateBuilder<ProjectTemplateRecipeResult, ProjectTemplateData>() {
private var _defModule: ModuleTemplateData? = null
@PublishedApi
internal val defModuleTemplate: ModuleTemplate? = null
@PublishedApi
internal val modules = mutableListOf<ModuleTemplate>()
@PublishedApi
internal val defModule: ModuleTemplateData
get() = checkNotNull(_defModule) { "Module template data not set" }
@@ -60,13 +60,13 @@ typealias AndroidModuleTemplateConfigurator = AndroidModuleTemplateBuilder.() ->
*
* @param block Function to configure the template.
*/
fun baseProject(projectName: StringParameter = projectNameParameter(),
inline fun baseProject(projectName: StringParameter = projectNameParameter(),
packageName: StringParameter = packageNameParameter(),
useKts: BooleanParameter = useKtsParameter(),
minSdk: EnumParameter<Sdk> = minSdkParameter(),
language: EnumParameter<Language> = projectLanguageParameter(),
projectVersionData: ProjectVersionData = ProjectVersionData(),
block: ProjectTemplateBuilder.() -> Unit
crossinline block: ProjectTemplateBuilder.() -> Unit
): ProjectTemplate {
return ProjectTemplateBuilder().apply {
@@ -148,8 +148,8 @@ fun baseProject(projectName: StringParameter = projectNameParameter(),
*
* @param block The module configurator.
*/
fun baseAndroidModule(isLibrary: Boolean = false,
block: AndroidModuleTemplateConfigurator
inline fun baseAndroidModule(isLibrary: Boolean = false,
crossinline block: AndroidModuleTemplateConfigurator
): ModuleTemplate {
return AndroidModuleTemplateBuilder().apply {
@@ -201,8 +201,8 @@ fun baseAndroidModule(isLibrary: Boolean = false,
* @param configurator The configurator to configure the template.
* @return The [FileTemplate].
*/
fun <R : FileTemplateRecipeResult> baseFile(dir: File,
configurator: FileTemplateBuilder<R>.() -> Unit
inline fun <R : FileTemplateRecipeResult> baseFile(dir: File,
crossinline configurator: FileTemplateBuilder<R>.() -> Unit
): FileTemplate<R> {
return FileTemplateBuilder<R>(dir).apply(configurator)
.build() as FileTemplate<R>
@@ -31,10 +31,10 @@ import com.itsaky.androidide.templates.base.util.AndroidManifestBuilder.Configur
* @param copyDefAssets Whether to copy the default Android assets (except `values` directory) to this module.
* @param block The module configurator.
*/
fun ProjectTemplateBuilder.defaultAppModule(name: String = ":app",
inline fun ProjectTemplateBuilder.defaultAppModule(name: String = ":app",
addAndroidX: Boolean = true,
copyDefAssets: Boolean = true,
block: AndroidModuleTemplateConfigurator
crossinline block: AndroidModuleTemplateConfigurator
) {
check(
defModuleTemplate == null) { "Default module has been already configured" }
@@ -52,8 +52,8 @@ internal fun ModuleTemplateBuilder.dependencies(): String {
* @param name The name of the field.
* @param configure A function to configure the field.
*/
fun TypeSpec.Builder.createConstant(type: TypeName, name: String, isPublic: Boolean,
configure: FieldSpec.Builder.() -> Unit
inline fun TypeSpec.Builder.createConstant(type: TypeName, name: String, isPublic: Boolean,
crossinline configure: FieldSpec.Builder.() -> Unit
) {
val accessMod = if (isPublic) Modifier.PUBLIC else Modifier.PRIVATE
FieldSpec.builder(type, name, accessMod, Modifier.STATIC, Modifier.FINAL)
@@ -68,8 +68,8 @@ fun TypeSpec.Builder.createConstant(type: TypeName, name: String, isPublic: Bool
* @param name The name of the field.
* @param configure A function to configure the field.
*/
fun TypeSpec.Builder.createField(type: TypeName, name: String, vararg modifiers: Modifier,
configure: FieldSpec.Builder.() -> Unit
inline fun TypeSpec.Builder.createField(type: TypeName, name: String, vararg modifiers: Modifier,
crossinline configure: FieldSpec.Builder.() -> Unit
) {
FieldSpec.builder(type, name, *modifiers).apply(configure).build().also { addField(it) }
}
@@ -79,7 +79,7 @@ fun TypeSpec.Builder.createField(type: TypeName, name: String, vararg modifiers:
*
* @param configure A function to configure the method.
*/
fun TypeSpec.Builder.createConstructor(configure: MethodSpec.Builder.() -> Unit) {
inline fun TypeSpec.Builder.createConstructor(crossinline configure: MethodSpec.Builder.() -> Unit) {
MethodSpec.constructorBuilder().apply(configure).build().also { addMethod(it) }
}
@@ -89,6 +89,6 @@ fun TypeSpec.Builder.createConstructor(configure: MethodSpec.Builder.() -> Unit)
* @param name The name of the method.
* @param configure A function to configure the method.
*/
fun TypeSpec.Builder.createMethod(name: String, configure: MethodSpec.Builder.() -> Unit) {
inline fun TypeSpec.Builder.createMethod(name: String, crossinline configure: MethodSpec.Builder.() -> Unit) {
MethodSpec.methodBuilder(name).apply(configure).build().also { addMethod(it) }
}
@@ -29,7 +29,10 @@ import com.itsaky.androidide.templates.TemplateRecipeResult
sealed class PrePostRecipeTemplateBuilder<R : TemplateRecipeResult> :
TemplateBuilder<R>() {
@PublishedApi
internal var preRecipe: TemplateRecipeConfigurator = {}
@PublishedApi
internal var postRecipe: TemplateRecipeFinalizer = {}
private var _recipe: TemplateRecipe<R>? = null
@@ -56,7 +59,10 @@ sealed class PrePostRecipeTemplateBuilder<R : TemplateRecipeResult> :
sealed class ExecutorDataTemplateBuilder<R : TemplateRecipeResult, D : TemplateData> :
PrePostRecipeTemplateBuilder<R>() {
@PublishedApi
internal var _executor: RecipeExecutor? = null
@PublishedApi
internal var _data: D? = null
val executor: RecipeExecutor
@@ -86,12 +86,12 @@ class AndroidModuleResManager {
* @param srcSet The source set.
* @param config The configuration for the resource type.
*/
fun AndroidModuleTemplateBuilder.createValuesResource(name: String,
inline fun AndroidModuleTemplateBuilder.createValuesResource(name: String,
type: ResourceType = VALUES,
srcSet: SrcSet = Main,
config: ConfigDescription = ConfigDescription(),
selfClose: Boolean = false,
configure: XmlBuilder.() -> Unit
crossinline configure: XmlBuilder.() -> Unit
) {
return createXmlResource(name, type, srcSet, config) {
createElement(name = "resources", closeStartTag = true,
@@ -107,11 +107,11 @@ class AndroidModuleResManager {
* @param srcSet The source set.
* @param config The configuration for the resource type.
*/
fun AndroidModuleTemplateBuilder.createXmlResource(name: String,
inline fun AndroidModuleTemplateBuilder.createXmlResource(name: String,
type: ResourceType,
srcSet: SrcSet = SrcSet.Main,
config: ConfigDescription = ConfigDescription(),
configure: XmlBuilder.() -> Unit = {}
crossinline configure: XmlBuilder.() -> Unit = {}
) {
val file = File(resDir(type, srcSet, config), "${name}.xml")
val builder = IndentedXmlBuilder().apply(configure)
@@ -146,11 +146,11 @@ class AndroidModuleResManager {
* @param config The configuration for the resource type.
* @param source Function which returns the source code for the resource.
*/
fun AndroidModuleTemplateBuilder.writeXmlResource(name: String,
inline fun AndroidModuleTemplateBuilder.writeXmlResource(name: String,
type: ResourceType,
srcSet: SrcSet = SrcSet.Main,
config: ConfigDescription = ConfigDescription(),
source: () -> String = { "" }
crossinline source: () -> String = { "" }
) {
writeXmlResource(name, type, srcSet, config, source())
}
@@ -91,8 +91,8 @@ class SourceWriter {
* @param className The name of the class.
* @param configure Function to configure the [TypeSpec.Builder].
*/
fun ModuleTemplateBuilder.createClass(packageName: String, className: String,
configure: TypeSpec.Builder.() -> Unit
inline fun ModuleTemplateBuilder.createClass(packageName: String, className: String,
crossinline configure: TypeSpec.Builder.() -> Unit
) {
return createJavaFile(packageName, className, ClassType(), configure)
}
@@ -104,8 +104,8 @@ class SourceWriter {
* @param className The name of the class.
* @param configure Function to configure the [TypeSpec.Builder].
*/
fun ModuleTemplateBuilder.createEnum(packageName: String, className: String,
configure: TypeSpec.Builder.() -> Unit
inline fun ModuleTemplateBuilder.createEnum(packageName: String, className: String,
crossinline configure: TypeSpec.Builder.() -> Unit
) {
return createJavaFile(packageName, className, EnumType(), configure)
}
@@ -117,8 +117,8 @@ class SourceWriter {
* @param className The name of the interface.
* @param configure Function to configure the [TypeSpec.Builder].
*/
fun ModuleTemplateBuilder.createInterface(packageName: String, className: String,
configure: TypeSpec.Builder.() -> Unit
inline fun ModuleTemplateBuilder.createInterface(packageName: String, className: String,
crossinline configure: TypeSpec.Builder.() -> Unit
) {
return createJavaFile(packageName, className, InterfaceType(), configure)
}
@@ -130,8 +130,8 @@ class SourceWriter {
* @param className The name of the interface.
* @param configure Function to configure the [TypeSpec.Builder].
*/
fun ModuleTemplateBuilder.createAnnotation(packageName: String, className: String,
configure: TypeSpec.Builder.() -> Unit
inline fun ModuleTemplateBuilder.createAnnotation(packageName: String, className: String,
crossinline configure: TypeSpec.Builder.() -> Unit
) {
return createJavaFile(packageName, className, AnnotationType(), configure)
}
@@ -144,8 +144,8 @@ class SourceWriter {
* @param type The type of the class.
* @param configure Function to configure the [TypeSpec.Builder].
*/
fun ModuleTemplateBuilder.createJavaFile(packageName: String, className: String, type: SourceType,
configure: TypeSpec.Builder.() -> Unit
inline fun ModuleTemplateBuilder.createJavaFile(packageName: String, className: String, type: SourceType,
crossinline configure: TypeSpec.Builder.() -> Unit
) {
val klass = ClassName.get(packageName, className)
val builder = type.builder(klass).apply(configure).also {
@@ -191,8 +191,8 @@ class SourceWriter {
* @param className The name of the class.
* @param source A function which returns the source code for the file.
*/
fun ModuleTemplateBuilder.writeJavaSrc(packageName: String, className: String,
srcSet: SrcSet = SrcSet.Main, source: () -> String
inline fun ModuleTemplateBuilder.writeJavaSrc(packageName: String, className: String,
srcSet: SrcSet = SrcSet.Main, crossinline source: () -> String
) {
writeJavaSrc(packageName, className, srcSet, source())
}
@@ -204,13 +204,14 @@ class SourceWriter {
* @param className The name of the class.
* @param source A function which returns the source code for the file.
*/
fun ModuleTemplateBuilder.writeKtSrc(packageName: String, className: String,
srcSet: SrcSet = SrcSet.Main, source: () -> String
inline fun ModuleTemplateBuilder.writeKtSrc(packageName: String, className: String,
srcSet: SrcSet = SrcSet.Main, crossinline source: () -> String
) {
writeKtSrc(packageName, className, srcSet, source())
}
private fun ModuleTemplateBuilder.write(file: JavaFile) {
@PublishedApi
internal fun ModuleTemplateBuilder.write(file: JavaFile) {
file.writeTo(mainJavaSrc())
}
}
@@ -32,7 +32,7 @@ internal fun BaseTemplateData.optonallyKts(file: String): String {
return if (useKts) "${file}.kts" else file
}
internal fun ProjectTemplateData.moduleNameToDir(name: String): File {
fun ProjectTemplateData.moduleNameToDir(name: String): File {
return File(this.projectDir, moduleNameToDirName(name).replace(':', '/').trim { it == '/' })
}
@@ -25,7 +25,7 @@ import org.eclipse.lemminx.dom.builder.XmlBuilder
* The [configure] function is used to configure everything inside the element and then
* the element is automatically closed.
*/
fun XmlBuilder.createElement(name: String, closeStartTag: Boolean = false, selfClose: Boolean = false, configure: XmlBuilder.() -> Unit) {
inline fun XmlBuilder.createElement(name: String, closeStartTag: Boolean = false, selfClose: Boolean = false, crossinline configure: XmlBuilder.() -> Unit) {
startElement(name, closeStartTag)
configure()
if (selfClose) {
@@ -349,19 +349,19 @@ class EnumParameterBuilder<T : Enum<*>> : TextFieldParameterBuilder<T>() {
/**
* Create a new [StringParameter] for accepting string input.
*/
fun stringParameter(block: StringParameterBuilder.() -> Unit
inline fun stringParameter(crossinline block: StringParameterBuilder.() -> Unit
): StringParameter = StringParameterBuilder().apply(block).build()
/**
* Create a new [BooleanParameter] for accepting boolean input.
*/
fun booleanParameter(block: BooleanParameterBuilder.() -> Unit
inline fun booleanParameter(crossinline block: BooleanParameterBuilder.() -> Unit
): BooleanParameter = BooleanParameterBuilder().apply(block).build()
fun <T : Enum<*>> enumParameter(block: EnumParameterBuilder<T>.() -> Unit
inline fun <T : Enum<*>> enumParameter(crossinline block: EnumParameterBuilder<T>.() -> Unit
): EnumParameter<T> = EnumParameterBuilder<T>().apply(block).build()
fun projectNameParameter(configure: StringParameterBuilder.() -> Unit = {}) =
inline fun projectNameParameter(crossinline configure: StringParameterBuilder.() -> Unit = {}) =
stringParameter {
name = string.project_app_name
default = "My Application"
@@ -371,7 +371,7 @@ fun projectNameParameter(configure: StringParameterBuilder.() -> Unit = {}) =
configure()
}
fun packageNameParameter(configure: StringParameterBuilder.() -> Unit = {}) =
inline fun packageNameParameter(crossinline configure: StringParameterBuilder.() -> Unit = {}) =
stringParameter {
name = string.package_name
default = "com.example.myapplication"
@@ -381,8 +381,8 @@ fun packageNameParameter(configure: StringParameterBuilder.() -> Unit = {}) =
configure()
}
fun projectLanguageParameter(
configure: EnumParameterBuilder<Language>.() -> Unit = {}
inline fun projectLanguageParameter(
crossinline configure: EnumParameterBuilder<Language>.() -> Unit = {}
) = enumParameter<Language> {
name = string.wizard_language
default = Java
@@ -395,7 +395,7 @@ fun projectLanguageParameter(
configure()
}
fun minSdkParameter(configure: EnumParameterBuilder<Sdk>.() -> Unit = {}) =
inline fun minSdkParameter(crossinline configure: EnumParameterBuilder<Sdk>.() -> Unit = {}) =
enumParameter<Sdk> {
name = string.minimum_sdk
default = Sdk.Lollipop
@@ -405,7 +405,7 @@ fun minSdkParameter(configure: EnumParameterBuilder<Sdk>.() -> Unit = {}) =
configure()
}
fun useKtsParameter(configure: BooleanParameterBuilder.() -> Unit = {}) =
inline fun useKtsParameter(crossinline configure: BooleanParameterBuilder.() -> Unit = {}) =
booleanParameter {
name = string.msg_use_kts
default = true
@@ -206,9 +206,9 @@ class TemplateWidgetViewProviderImpl : ITemplateWidgetViewProvider {
}.root
}
private fun TextFieldParameter<*>.configureTextField(context: Context,
private inline fun TextFieldParameter<*>.configureTextField(context: Context,
root: TextInputLayout,
onTextChanged: (String) -> Unit = {}
crossinline onTextChanged: (String) -> Unit = {}
) {
root.setHint(name)
resetStartAndEndIcons(context, root)
@@ -54,14 +54,14 @@ internal fun AndroidModuleTemplateBuilder.templateAsset(name: String,
return "templates/${name}/${path}"
}
internal fun baseProjectImpl(
internal inline fun baseProjectImpl(
projectName: StringParameter = projectNameParameter(),
packageName: StringParameter = packageNameParameter(),
useKts: BooleanParameter = useKtsParameter(),
minSdk: EnumParameter<Sdk> = minSdkParameter(),
language: EnumParameter<Language> = projectLanguageParameter(),
projectVersionData: ProjectVersionData = ProjectVersionData(),
block: ProjectTemplateBuilder.() -> Unit
crossinline block: ProjectTemplateBuilder.() -> Unit
): ProjectTemplate =
baseProject(projectName = projectName, packageName = packageName,
useKts = useKts, minSdk = minSdk, language = language,
@@ -26,16 +26,16 @@ import com.itsaky.androidide.templates.base.AndroidModuleTemplateBuilder
import com.itsaky.androidide.templates.base.ExecutorDataTemplateBuilder
import com.itsaky.androidide.templates.base.ProjectTemplateBuilder
internal fun <R : TemplateRecipeResult> ExecutorDataTemplateBuilder<*, *>.createRecipe(
action: RecipeExecutor.() -> R
internal inline fun <R : TemplateRecipeResult> ExecutorDataTemplateBuilder<*, *>.createRecipe(
crossinline action: RecipeExecutor.() -> R
): TemplateRecipe<R> {
return TemplateRecipe {
return@TemplateRecipe executor.run(action)
}
}
internal fun AndroidModuleTemplateBuilder.createRecipe(
action: RecipeExecutor.() -> Unit
internal inline fun AndroidModuleTemplateBuilder.createRecipe(
crossinline action: RecipeExecutor.() -> Unit
): TemplateRecipe<ModuleTemplateRecipeResult> {
return TemplateRecipe {
executor.run(action)
@@ -43,8 +43,8 @@ internal fun AndroidModuleTemplateBuilder.createRecipe(
}
}
internal fun ProjectTemplateBuilder.createRecipe(
action: RecipeExecutor.() -> Unit
internal inline fun ProjectTemplateBuilder.createRecipe(
crossinline action: RecipeExecutor.() -> Unit
): TemplateRecipe<ProjectTemplateRecipeResult> {
return TemplateRecipe {
executor.run(action)
@@ -23,8 +23,8 @@ import com.itsaky.androidide.templates.base.modules.android.ManifestActivity
import com.itsaky.androidide.templates.base.util.SourceWriter
import com.itsaky.androidide.templates.base.util.withXmlDecl
internal fun AndroidModuleTemplateBuilder.writeMainActivity(
writer: SourceWriter, ktSrc: () -> String, javaSrc: () -> String
internal inline fun AndroidModuleTemplateBuilder.writeMainActivity(
writer: SourceWriter, crossinline ktSrc: () -> String, crossinline javaSrc: () -> String
) {
val className = "MainActivity"
writer.apply {