diff --git a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetProjectSchema.kt b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetProjectSchema.kt index 5cd0897..8004c17 100644 --- a/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetProjectSchema.kt +++ b/gradle-client/src/jvmMain/kotlin/org/gradle/client/ui/connected/actions/GetProjectSchema.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.text.font.FontFamily import org.gradle.declarative.dsl.schema.* import org.gradle.declarative.dsl.tooling.models.DeclarativeSchemaModel @@ -18,40 +19,105 @@ class GetProjectSchema : GetModelAction { style = MaterialTheme.typography.titleMedium ) Text( - text = "Schema: ${model.projectSchema.toHumanReadable()}", - style = MaterialTheme.typography.labelSmall + text = "Available Software Types:\n${model.projectSchema.describeSoftwareTypes()}", + style = MaterialTheme.typography.labelSmall.copy(fontFamily = FontFamily.Monospace), ) } - private fun AnalysisSchema.toHumanReadable(): String { + private fun AnalysisSchema.dataClassFor(typeRef: DataTypeRef.Name): DataClass = + dataClassesByFqName.getValue(typeRef.fqName) + + private fun AnalysisSchema.describeSoftwareTypes(): String { val memberFunctions = this.topLevelReceiverType.memberFunctions return buildString { - memberFunctions.forEach { + memberFunctions.forEach { softwareType -> + appendLine() + appendDescription(this@describeSoftwareTypes, softwareType) + appendLine() + } + } + } + + private val indentChars = " " + + @Suppress("NestedBlockDepth") + private fun StringBuilder.appendDescription( + schema: AnalysisSchema, + function: SchemaMemberFunction, + indentLevel: Int = 0 + ) { + when (val functionSemantics = function.semantics) { + + // Configuring blocks + is FunctionSemantics.AccessAndConfigure -> { + append(indentChars.repeat(indentLevel)) + append(function.simpleName) + append(" {") appendLine() - append("\t") - append(it.receiver.toHumanReadable()) - append(".") - append(it.simpleName) + when (val blockType = functionSemantics.configuredType) { + is DataTypeRef.Name -> { + val blockDataClass = schema.dataClassFor(blockType) + blockDataClass.properties.forEach { property -> + val propTypeName = when (val propType = property.valueType) { + is DataTypeRef.Type -> propType.dataType.toString() + is DataTypeRef.Name -> propType.toHumanReadable() + } + append(indentChars.repeat(indentLevel + 1)) + append("${property.name}: $propTypeName") + appendLine() + } + blockDataClass.memberFunctions.forEach { subBlock -> + appendDescription(schema, subBlock, indentLevel + 1) + appendLine() + } + } + + is DataTypeRef.Type -> TODO("Block '${function.simpleName}' type is not a type ref") + } + append(indentChars.repeat(indentLevel)) + append("}") + } + + // Factory function + is FunctionSemantics.Pure -> { + append(indentChars.repeat(indentLevel + 1)) + append(function.simpleName) + append("(") + append(function.parameters.joinToString { dp -> dp.toHumanReadable() }) + append("): ") + append(function.returnValueType.toHumanReadable()) + } + + // Add and configure function + is FunctionSemantics.AddAndConfigure -> { + append(indentChars.repeat(indentLevel + 1)) + append(function.simpleName) append("(") - append(it.parameters.joinToString {dp -> dp.toHumanReadable()}) + append(function.parameters.joinToString { dp -> dp.toHumanReadable() }) append(")") - append(" -> ") - append(it.returnValueType.toHumanReadable()) + } + + is FunctionSemantics.Builder -> { + append(indentChars.repeat(indentLevel + 1)) + append("TODO Block '${function.simpleName}' is a Builder") } } } private fun DataTypeRef.toHumanReadable(): String = when (this) { - is DataTypeRef.Name -> fqName.qualifiedName + is DataTypeRef.Name -> fqName.simpleName + is DataTypeRef.Type -> toHumanReadable() + } - is DataTypeRef.Type -> when (dataType) { - is DataType.NullType -> "null" - is DataType.UnitType -> "void" - is DataType.ConstantType<*> -> (dataType as DataType.ConstantType<*>).constantType.simpleName - is DataClass -> (dataType as DataClass).name.qualifiedName - } + private fun DataTypeRef.Type.toHumanReadable(): String = + when (val type = this.dataType) { + is DataType.NullType -> "null" + is DataType.UnitType -> Unit::class.simpleName!! + is DataType.ConstantType<*> -> type.toString() + is DataClass -> type.name.simpleName } - private fun DataParameter.toHumanReadable(): String = type.toHumanReadable() + private fun DataParameter.toHumanReadable(): String = + type.toHumanReadable() }