Skip to content

Conversation

@TBSten
Copy link
Owner

@TBSten TBSten commented Dec 15, 2025

Summary

  • Implemented a Kotlin Symbol Processing (KSP) plugin that automatically generates factory functions for PreviewLabField
  • Added @AutoGenerateField<T> annotation for marking objects to auto-generate field factories
  • Supports automatic generation for Primitives, Enums, Objects, Data Classes, and Sealed Types
  • Significantly reduces boilerplate code for common field type definitions

Changes

Core Implementation

  • TypeClassification.kt: Sealed interface for type classification (Primitive, Enum, Object, DataClass, Sealed, Unsupported)
  • TypeClassifier.kt: Classifies KSType into TypeClassification categories with caching support
  • CodeGenerator.kt: Generates extension functions and helper objects based on type classification
  • AutoGenerateFieldProcessor.kt: Main processor orchestrating the code generation workflow

New APIs

  • @AutoGenerateField<T>(name: String = "", autoLabelByTypeName: Boolean = false): Annotation for auto-generation
  • ChildFieldScope<Value>: Scope class for accessing label and initialValue in child field factories
  • enumField(): Helper function for enum field generation

Gradle Integration

  • Added generateAutoField property to ComposePreviewLabExtension (default: true)
  • Configured KSP argument passing from Gradle Plugin

Test Infrastructure

  • Created integrationTest/autoGenerateFieldTest module for compile-time verification
  • Defined test types covering all supported classifications (T1-T5):
    • T1: Primitive types (String, Int)
    • T2: Enum (SimpleStatus)
    • T3: Object types (SingletonState, EmptyState)
    • T4: Data Class (SimpleData with nested fields)
    • T5: Sealed Interface (SimpleSealed with multiple subclasses)

Generated Code Examples

Primitive Type

fun Fields.string(label: String, initialValue: String): MutablePreviewLabField<String>

Enum Type

fun Fields.simpleStatus(label: String, initialValue: SimpleStatus): MutablePreviewLabField<SimpleStatus>

Data Class (Combined Field)

fun Fields.simpleData(
    label: String,
    initialValue: SimpleData,
    nameField: ChildFieldScope<String>.() -> MutablePreviewLabField<String> = ...,
    countField: ChildFieldScope<Int>.() -> MutablePreviewLabField<Int> = ...,
): MutablePreviewLabField<SimpleData>

Test plan

  • Ran ./gradlew ktlintCheck - All style checks pass
  • Ran ./gradlew :ksp-plugin:build :gradle-plugin:build - Build successful
  • Ran cd integrationTest && ./gradlew :autoGenerateFieldTest:compileCommonMainKotlinMetadata - KSP code generation successful
  • Ran ./gradlew :autoGenerateFieldTest:compileKotlinJvm - Generated code compiles correctly
  • Verified generated code includes @file:OptIn(ExperimentalComposePreviewLabApi::class)
  • Verified API dumps updated for annotation, field, gradle-plugin, ksp-plugin modules
  • Manual verification: Generated factory functions are correct and type-safe

🤖 Generated with Claude Code

Co-Authored-By: Claude [email protected]

Add the @AutoGenerateField<T> annotation for marking objects to auto-generate
PreviewLabField factory functions via KSP.

- Added @AutoGenerateField<T> with `name` and `autoLabelByTypeName` parameters
- Added KspArg.generateAutoField constant for KSP argument passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
TBSten and others added 5 commits December 16, 2025 00:28
Add helper classes and functions for auto-generated field factories.

- ChildFieldScope<Value>: Scope class providing label and initialValue to child field factories
- enumField(): Inline function for creating enum fields with automatic entry detection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Add generateAutoField property to ComposePreviewLabExtension for enabling/disabling
the auto-generation feature (default: true).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Implement the KSP processor for auto-generating PreviewLabField factory functions.

## Components
- TypeClassification: Sealed interface for type classification
  (Primitive, Enum, Object, DataClass, Sealed, Unsupported)
- TypeClassifier: Classifies KSType into TypeClassification with caching
- CodeGenerator: Generates factory extension functions and helper objects
- AutoGenerateFieldProcessor: Main processor orchestrating the workflow

## Supported Types
- Primitives (String, Int, Long, Float, Double, Boolean, Byte)
- Enum classes
- Object declarations (including data objects)
- Data classes (generates combined fields)
- Sealed interfaces/classes (generates polymorphic fields)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Add integration test module to verify the @AutoGenerateField KSP processor
generates correct and compilable code.

## Test Types
- T1: Primitives (String, Int)
- T2: Enum (SimpleStatus)
- T3: Objects (SingletonState, EmptyState)
- T4: Data Class (SimpleData)
- T5: Sealed Interface (SimpleSealed)

## Verification
Compilation success indicates generated code is correct and type-safe.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@TBSten TBSten force-pushed the feature/auto-generate-combined-field-2 branch from b2bf65a to 4556cea Compare December 15, 2025 15:29
TBSten and others added 3 commits December 16, 2025 02:41
Implement complete edge case handling for @AutoGenerateField KSP processor:

## Edge Cases Supported
- T6: Nested 2-level data class
- T7: Sealed interface with data class subclasses
- T8: Data class with unsupported types (generates TODO)
- T9: 3-level nesting
- T10: Nested sealed interfaces (Sealed inside Sealed)
- T11: 5-level deep nesting
- T12: internal visibility modifier
- T13: autoLabelByTypeName parameter
- T14: Custom function name via name parameter

## Key Fixes
- Fixed nested label generation (use correct property name labels)
- Fixed name collision for ChildFieldFactories by prefixing with target object name
- Added TODO() for unsupported types instead of invalid comments
- Proper handling of nested DataClass and Sealed types recursively

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Reflects the rename of EnumField -> enumField to follow Kotlin naming conventions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@TBSten TBSten requested a review from Copilot December 15, 2025 18:00
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a Kotlin Symbol Processing (KSP) plugin that automatically generates factory functions for creating PreviewLabField instances. The plugin uses the new @AutoGenerateField<T> annotation to mark types for code generation, significantly reducing boilerplate when defining preview fields for various Kotlin types.

Key Changes

  • Introduced KSP-based code generation supporting primitives, enums, objects, data classes, and sealed types
  • Added @AutoGenerateField<T> annotation with configurable name and automatic labeling options
  • Integrated with existing Gradle plugin via generateAutoField property (enabled by default)

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated no comments.

Show a summary per file
File Description
ksp-plugin/src/main/kotlin/.../TypeClassification.kt Defines sealed interface for categorizing Kotlin types with metadata
ksp-plugin/src/main/kotlin/.../TypeClassifier.kt Implements type classification logic with caching
ksp-plugin/src/main/kotlin/.../CodeGenerator.kt Generates factory extension functions based on type classification
ksp-plugin/src/main/kotlin/.../AutoGenerateFieldProcessor.kt Main KSP processor coordinating code generation workflow
ksp-plugin/src/main/kotlin/.../ComposePreviewLabKspProcessor.kt Integrates AutoGenerateField processor into existing KSP pipeline
field/src/commonMain/kotlin/.../EnumField.kt Adds helper functions for enum field creation
field/src/commonMain/kotlin/.../ChildFieldScope.kt New scope class providing context for child field factories
gradle-plugin/src/main/kotlin/.../ComposePreviewLabExtension.kt Adds generateAutoField configuration property
annotation/src/commonMain/kotlin/.../AutoGenerateField.kt New annotation for marking types for auto-generation
annotation/src/commonMain/kotlin/.../KspArg.kt Adds KSP argument constant for feature flag
integrationTest/autoGenerateFieldTest/* Integration test module verifying generated code compiles
/api/ Updated API dumps for public API changes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Add compile-time verification tests for all edge cases (T6-T14):
- T6: Nested data class (2 levels)
- T7: Sealed interface with data class subclasses
- T9: Nested data class (3 levels)
- T10: Nested sealed interfaces
- T11: Deep nesting (5 levels)
- T12: Internal visibility
- T13: autoLabelByTypeName option
- T14: Custom name option

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@TBSten TBSten marked this pull request as draft December 15, 2025 18:04
TBSten and others added 2 commits December 24, 2025 01:14
KSP plugin の内部実装クラスを internal に変更し、public API を最小化。
ComposePreviewLabKspProcessorProvider のみを public として残す。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants