Repository: AntonButov/dagger-dsl
Pull request #13: Writer
Author: login: AntonButov
Created: 2025-03-22T17:49:18Z | Merged: 2025-04-05T10:43:49Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Enhanced component naming with a consistent default value to improve reliability.
  - Introduced dynamic file generation capabilities for creating standard Kotlin interfaces.
  - Expanded mapping functionality for generating interface representations.
  - Integrated new plugins and libraries to bolster dependency injection, code generation, and testing support.

- **Tests**
  - Added comprehensive tests to validate component mapping and file generation processes.

- **Chores**
  - Updated dependency versions for improved performance and stability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/dagger-dsl-core/src/main/kotlin/dagger/dsl/core/dsl.kt b/dagger-dsl-core/src/main/kotlin/dagger/dsl/core/dsl.kt
index 2f9ab08..0a27ebc 100644
--- a/dagger-dsl-core/src/main/kotlin/dagger/dsl/core/dsl.kt
+++ b/dagger-dsl-core/src/main/kotlin/dagger/dsl/core/dsl.kt
@@ -6,7 +6,7 @@ fun component(dsl: ComponentBuilder.() -> Unit): Component {
 
 class ComponentBuilder {
     private var isSingleton = false
-    var name: String? = null
+    var name: String = "component"
     private var modules: MutableList<Module> = mutableListOf()
 
     fun singleton() {
@@ -22,7 +22,7 @@ class ComponentBuilder {
 
 data class Component(
     val isSingleton: Boolean,
-    val name: String?,
+    val name: String,
     val modules: List<Module>,
 )
 
diff --git a/dagger-dsl-processor/build.gradle.kts b/dagger-dsl-processor/build.gradle.kts
index b4bb79c..f66f1f2 100644
--- a/dagger-dsl-processor/build.gradle.kts
+++ b/dagger-dsl-processor/build.gradle.kts
@@ -5,6 +5,7 @@ import java.nio.file.Paths
 
 plugins {
     alias(libs.plugins.kotlin.jvm)
+    alias(libs.plugins.ksp)
 }
 
 group = "com.dagger.dsl"
@@ -12,9 +13,13 @@ version = "1.0-SNAPSHOT"
 
 dependencies {
     implementation(project(":dagger-dsl-core"))
+    ksp(libs.code.factory)
     implementation(libs.ksp)
     implementation(libs.compile.embedded)
     implementation(kotlin("stdlib"))
+    implementation(libs.kotlin.poet)
+    implementation(libs.dagger)
+    implementation(libs.mockk)
 
     testImplementation(libs.kotest.runner)
     api(libs.compilation) // todo rework to testImplementation
diff --git a/dagger-dsl-processor/dagger-dsl-core.jar b/dagger-dsl-processor/dagger-dsl-core.jar
index 1f09416..4faa14e 100644
Binary files a/dagger-dsl-processor/dagger-dsl-core.jar and b/dagger-dsl-processor/dagger-dsl-core.jar differ
diff --git a/dagger-dsl-processor/src/main/kotlin/mappers.kt b/dagger-dsl-processor/src/main/kotlin/mappers.kt
new file mode 100644
index 0000000..6d7a85b
--- /dev/null
+++ b/dagger-dsl-processor/src/main/kotlin/mappers.kt
@@ -0,0 +1,17 @@
+import com.squareup.kotlinpoet.ClassName
+import com.squareup.kotlinpoet.TypeSpec
+import dagger.dsl.core.Component
+
+interface ComponentToFileSpecMapper {
+    fun map(component: Component): TypeSpec
+}
+
+class ComponentToFileSpecMapperImpl : ComponentToFileSpecMapper {
+    override fun map(component: Component): TypeSpec {
+        val generatedClass =
+            TypeSpec.interfaceBuilder(component.name)
+                .addAnnotation(ClassName(dagger.Component::class.java.packageName, dagger.Component::class.java.simpleName))
+                .build()
+        return generatedClass
+    }
+}
diff --git a/dagger-dsl-processor/src/main/kotlin/usescases/Writer.kt b/dagger-dsl-processor/src/main/kotlin/usescases/Writer.kt
new file mode 100644
index 0000000..32a9f5f
--- /dev/null
+++ b/dagger-dsl-processor/src/main/kotlin/usescases/Writer.kt
@@ -0,0 +1,36 @@
+package usescases
+
+import com.google.devtools.ksp.processing.CodeGenerator
+import com.google.devtools.ksp.processing.Dependencies
+
+interface Writer {
+    fun write(
+        packageName: String,
+        fileName: String,
+        component: String,
+    )
+}
+
+class WriterImpl(private val codeGenerator: CodeGenerator) : Writer {
+    override fun write(
+        packageName: String,
+        fileName: String,
+        component: String,
+    ) {
+        val file =
+            codeGenerator.createNewFile(
+                dependencies = Dependencies(true),
+                packageName = packageName,
+                fileName = fileName,
+            )
+        file.bufferedWriter().use { writer ->
+            writer.write(
+                """
+                package $packageName
+                
+                $component
+                """.trimIndent(),
+            )
+        }
+    }
+}
diff --git a/dagger-dsl-processor/src/test/kotlin/MappersTest.kt b/dagger-dsl-processor/src/test/kotlin/MappersTest.kt
new file mode 100644
index 0000000..c581249
--- /dev/null
+++ b/dagger-dsl-processor/src/test/kotlin/MappersTest.kt
@@ -0,0 +1,40 @@
+package usescases.component
+
+import ComponentToFileSpecMapper
+import ComponentToFileSpecMapperImpl
+import dagger.dsl.core.component
+import io.kotest.core.spec.style.StringSpec
+import io.kotest.matchers.shouldBe
+
+class MappersTest : StringSpec({
+
+    val mapper: ComponentToFileSpecMapper = ComponentToFileSpecMapperImpl()
+
+    "default component" {
+        val component = component {}
+
+        val fileSpec = mapper.map(component)
+        fileSpec.toString() shouldBe
+            """
+                |@dagger.Component
+                |public interface component
+                |
+            """.trimMargin()
+    }
+
+    "simple named case" {
+        val component =
+            component {
+                name = "myComponent"
+            }
+
+        val fileSpec = mapper.map(component)
+
+        fileSpec.toString() shouldBe
+            """
+                |@dagger.Component
+                |public interface myComponent
+                |
+            """.trimMargin()
+    }
+})
diff --git a/dagger-dsl-processor/src/test/kotlin/WriterTest.kt b/dagger-dsl-processor/src/test/kotlin/WriterTest.kt
new file mode 100644
index 0000000..4136ea6
--- /dev/null
+++ b/dagger-dsl-processor/src/test/kotlin/WriterTest.kt
@@ -0,0 +1,34 @@
+package usescases.component
+
+import com.google.devtools.ksp.processing.CodeGenerator
+import io.kotest.core.spec.style.StringSpec
+import io.mockk.mockk
+import io.mockk.verify
+import usescases.Writer
+import usescases.WriterImpl
+
+class WriterTest : StringSpec({
+
+    lateinit var codeGenerator: CodeGenerator
+    lateinit var writer: Writer
+
+    beforeEach {
+        codeGenerator = mockk<CodeGenerator>(relaxed = true)
+        writer = WriterImpl(codeGenerator)
+    }
+
+    "should create a new file with the correct content" {
+        val packageName = "com.example"
+        val fileName = "Di.kt"
+        val component = "MyComponent"
+        writer.write(packageName, fileName, component)
+
+        verify {
+            codeGenerator.createNewFile(
+                dependencies = any(),
+                packageName = packageName,
+                fileName = "Di.kt",
+            )
+        }
+    }
+})
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 72ef1c1..ee06847 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -4,6 +4,10 @@ ksp = "1.9.25-1.0.20"
 kotest = "5.9.1"
 compilation = "2.0.0"
 ktlint = "12.2.0"
+kotlinPoet = "1.18.0"
+code-factory = "1.0.1"
+dagger = "2.55"
+mockk = "1.13.17"
 
 [libraries]
 kotest-core = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest"}
@@ -11,6 +15,10 @@ kotest-runner = { module = "io.kotest:kotest-runner-junit5", version.ref = "kote
 compilation = { module = "com.github.antonbutov:compilation", version.ref = "compilation" }
 ksp = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" }
 compile-embedded = { module = "org.jetbrains.kotlin:kotlin-compiler-embeddable", version.ref = "kotlin"}
+kotlin-poet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinPoet" }
+code-factory = { module = "io.github.antonbutov:code-factory-processor", version.ref = "code-factory" }
+dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" }
+mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
 
 [bundles]
 


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🧹 Nitpick comments (6)</summary><blockquote>

<details>
<summary>dagger-dsl-processor/src/test/kotlin/WriterTest.kt (1)</summary><blockquote>

`26-32`: **Consider verifying file content creation.**

The test only verifies that `createNewFile` is called with the correct parameters but doesn't verify the actual content being written. Consider adding verification for the content being passed to the file creation.


```diff
verify {
    codeGenerator.createNewFile(
        dependencies = any(),
        packageName = packageName,
        fileName = "Di.kt",
+       content = any()
    )
}
```

</blockquote></details>
<details>
<summary>dagger-dsl-processor/src/main/kotlin/mappers.kt (1)</summary><blockquote>

`9-18`: **Consider adding more flexibility to the mapper implementation.**

The current implementation creates a basic interface with only a name and annotation. Consider enhancing it to support additional features like module dependencies, provision methods, etc.


```diff
class ComponentToFileSpecMapperImpl : ComponentToFileSpecMapper {
    override fun map(component: Component): TypeSpec {
        val generatedClass =
            TypeSpec.interfaceBuilder(component.name)
                .addAnnotation(ClassName(dagger.Component::class.java.packageName, dagger.Component::class.java.simpleName))
+               // Add support for modules if present
+               // component.modules?.let { modules ->
+               //     val modulesAnnotation = AnnotationSpec.builder(ClassName(dagger.Component::class.java.packageName, "modules"))
+               //         .addMember("modules", modules.joinToString { "%T::class" }, *modules.map { ClassName.bestGuess(it) }.toTypedArray())
+               //         .build()
+               //     addAnnotation(modulesAnnotation)
+               // }
                .build()

        return generatedClass
    }
}
```

</blockquote></details>
<details>
<summary>dagger-dsl-processor/src/test/kotlin/MappersTest.kt (1)</summary><blockquote>

`13-23`: **Test for interface modifiers and other attributes.**

The test only verifies the string representation of the generated interface. Consider testing specific attributes like modifiers, annotations, etc., directly instead of relying on string representation which might be brittle.


```diff
"default component" {
    val component = component {}

    val fileSpec = mapper.map(component)
-   fileSpec.toString() shouldBe
-       """
-           |@dagger.Component
-           |public interface component
-           |
-       """.trimMargin()
+   fileSpec.toString() shouldBe """
+       |@dagger.Component
+       |public interface component
+       |
+   """.trimMargin()
+   
+   // Additional assertions on the TypeSpec properties
+   fileSpec.kind shouldBe TypeSpec.Kind.INTERFACE
+   fileSpec.name shouldBe "component"
+   fileSpec.annotations.size shouldBe 1
+   fileSpec.annotations[0].className.simpleName shouldBe "Component"
}
```

</blockquote></details>
<details>
<summary>dagger-dsl-processor/src/main/kotlin/usescases/Writer.kt (2)</summary><blockquote>

`14-36`: **Good implementation with resource management, but missing error handling.**

The implementation correctly uses the `use` function with `bufferedWriter()` to ensure proper resource cleanup. However, there's no error handling for potential I/O exceptions that could occur during file writing operations.


Consider adding try-catch blocks to handle potential exceptions:

```diff
override fun write(
    packageName: String,
    fileName: String,
    component: String,
) {
+   try {
        val file =
            codeGenerator.createNewFile(
                dependencies = Dependencies(true),
                packageName = packageName,
                fileName = fileName,
            )
        file.bufferedWriter().use { writer ->
            writer.write(
                """
                package $packageName
                
                $component
                """.trimIndent(),
            )
        }
+   } catch (e: Exception) {
+       // Handle or rethrow with more context
+       throw IllegalStateException("Failed to write file $fileName in package $packageName", e)
+   }
}
```

---

`1-36`: **Missing KDoc documentation for public API.**

The interface and class lack KDoc documentation that would help users understand their purpose and proper usage.


Add KDoc comments to document the interface and implementation:

```diff
package usescases

import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies

+/**
+ * Interface for writing generated Kotlin code to files.
+ */
interface Writer {
+   /**
+    * Writes Kotlin code to a file.
+    *
+    * @param packageName The package name for the generated code.
+    * @param fileName The name of the file to be created.
+    * @param component The Kotlin code to be written to the file.
+    */
    fun write(
        packageName: String,
        fileName: String,
        component: String,
    )
}

+/**
+ * Implementation of Writer that uses KSP's CodeGenerator to write files.
+ *
+ * @property codeGenerator The KSP code generator used to create new files.
+ */
class WriterImpl(private val codeGenerator: CodeGenerator) : Writer {
    override fun write(
        packageName: String,
        fileName: String,
        component: String,
    ) {
        // Implementation remains the same
    }
}
```

</blockquote></details>
<details>
<summary>gradle/libs.versions.toml (1)</summary><blockquote>

`7-7`: **Inconsistent naming convention.**

There's an inconsistency in the naming convention for KotlinPoet - the version reference uses camelCase (`kotlinPoet`) while the library declaration uses kebab-case (`kotlin-poet`).


Consider standardizing the naming convention:

```diff
[versions]
- kotlinPoet = "1.18.0"
+ kotlin-poet = "1.18.0"

[libraries]
- kotlin-poet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinPoet" }
+ kotlin-poet = { module = "com.squareup:kotlinpoet", version.ref = "kotlin-poet" }
```

Or:

```diff
[versions]
kotlinPoet = "1.18.0"

[libraries]
- kotlin-poet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinPoet" }
+ kotlinPoet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinPoet" }
```


Also applies to: 18-18

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between a7992bec963a271af726ab5235efd130aeea0e5e and 03c7ea3294d18892324f17cb620aef985035b14e.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `dagger-dsl-processor/dagger-dsl-core.jar` is excluded by `!**/*.jar`

</details>

<details>
<summary>📒 Files selected for processing (7)</summary>

* `dagger-dsl-core/src/main/kotlin/dagger/dsl/core/dsl.kt` (2 hunks)
* `dagger-dsl-processor/build.gradle.kts` (1 hunks)
* `dagger-dsl-processor/src/main/kotlin/mappers.kt` (1 hunks)
* `dagger-dsl-processor/src/main/kotlin/usescases/Writer.kt` (1 hunks)
* `dagger-dsl-processor/src/test/kotlin/MappersTest.kt` (1 hunks)
* `dagger-dsl-processor/src/test/kotlin/WriterTest.kt` (1 hunks)
* `gradle/libs.versions.toml` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (1)</summary>

<details>
<summary>dagger-dsl-processor/src/test/kotlin/MappersTest.kt (1)</summary><blockquote>

<details>
<summary>dagger-dsl-core/src/main/kotlin/dagger/dsl/core/dsl.kt (1)</summary>

* `component` (3-5)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (9)</summary><blockquote>

<details>
<summary>dagger-dsl-processor/src/test/kotlin/WriterTest.kt (1)</summary>

`20-33`: <details>
<summary>✅ Verification successful</summary>

**Verify the filename parameter usage.**

I notice that while `fileName` is passed as a parameter to `writer.write()` on line 24, the verification on line 30 is checking for a hardcoded value "Di.kt". This suggests that the `WriterImpl` implementation might be ignoring the `fileName` parameter.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check the WriterImpl implementation to see if it uses the fileName parameter
fd -e kt -x grep -l "class WriterImpl" {} \; | xargs cat
```

Length of output: 945

---



</details>

**Subject: Verified Correct Usage of the FileName Parameter**

After verifying the implementation, the `WriterImpl` properly passes the `fileName` parameter to `codeGenerator.createNewFile()`. The test case passes `"Di.kt"` as the parameter, and the implementation uses it directly, meaning there is no hardcoding issue.

- **File:** `dagger-dsl-processor/src/test/kotlin/WriterTest.kt`  
- **Detail:** The `WriterImpl` implementation correctly uses the `fileName` parameter (see `fileName = fileName` in the call to `createNewFile()`), matching the test expectation of `"Di.kt"`.

</details>
<details>
<summary>dagger-dsl-processor/build.gradle.kts (2)</summary>

`20-22`: **LGTM! Adding necessary dependencies.**

The added dependencies for Kotlin Poet, Dagger, and MockK are appropriate for the code generation and testing functionality being implemented.

---

`16-16`: <details>
<summary>❓ Verification inconclusive</summary>

**Verify code.factory version compatibility.**

The `code.factory` library is added as a KSP dependency. Ensure that the version is compatible with the current KSP version to avoid potential processing issues.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check the versions.toml file for the code.factory version
fd "versions.toml" -x grep -A 10 "code.factory" {}
```

Length of output: 1127

---



</details>

**Action: Verify Compatibility of code-factory 1.0.1 with KSP**

- The `versions.toml` file confirms that the `code-factory` dependency is set to version **1.0.1**.
- The current KSP dependency is referenced via the `ksp` key in both the libraries and plugins sections.
- Please double-check the documentation for the `code-factory-processor` (version 1.0.1) to ensure it is fully compatible with the KSP version you are using. Any known issues or breaking changes should be addressed to avoid potential processing problems.

</details>
<details>
<summary>dagger-dsl-processor/src/main/kotlin/usescases/Writer.kt (1)</summary>

`6-12`: **Well-designed interface with clear purpose.**

The `Writer` interface has a clean, focused API with a single responsibility. This follows good interface design principles.

</details>
<details>
<summary>dagger-dsl-core/src/main/kotlin/dagger/dsl/core/dsl.kt (3)</summary>

`9-9`: **Good enhancement of type safety.**

Changing `name` from a nullable type with null default to a non-nullable type with a default value improves type safety and eliminates potential null-related issues.

---

`25-25`: **Consistent non-nullable property.**

Making the `name` property non-nullable in the `Component` data class maintains consistency with the change in the `ComponentBuilder`. This eliminates the need for null checks when using this property.

---

`9-9`: <details>
<summary>❓ Verification inconclusive</summary>

**Potential breaking change that requires verification.**

Converting nullable properties to non-nullable ones is potentially a breaking change if external code depends on the nullable behavior.





Also applies to: 25-25

---

🏁 Script executed:

```shell
#!/bin/bash
# Check for code that might be accessing these properties and handling nullability
# This will help identify potential breaking changes

# Look for usages of the Component class
echo "Searching for places that might be affected by Component.name nullability change:"
rg -A 2 -B 2 "Component\(" --type kotlin

# Look for places where name might be checked for null
echo "Searching for null checks on name property:"
rg "\.name\s*[!=]=\s*null" --type kotlin
```

Length of output: 944

---



</details>

**Action Required: Verify External Impact on `Component.name` Non-nullability**  
Our searches indicate that within the core DSL file, there are no explicit null-checks for the `name` property, and its usage appears confined to internal construction (as seen in the `build()` function and `Component` data class). However, since external code might depend on `name` being nullable, this change could still break consumers unaware of the modification. Please manually verify that external usage (if any) does not rely on `name`’s nullable behavior.

- **File:** `dagger-dsl-core/src/main/kotlin/dagger/dsl/core/dsl.kt`  
  - **Line 9:** Declaration of `var name: String = "component"`
  - **Line 25:** Occurrences related to `Component` construction  
- **Next Steps:**  
  - Confirm that no external consumers or downstream components are expecting `name` to be nullable.
  - Update documentation or notify users if necessary to mitigate potential breaking changes.

</details>
<details>
<summary>gradle/libs.versions.toml (2)</summary>

`7-10`: **Dependencies with appropriate versions.**

The added version references for KotlinPoet, code-factory, Dagger, and MockK look appropriate for the project.

---

`18-21`: **Well-structured library declarations.**

The library declarations properly reference the version constants defined earlier and use the correct module paths.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T18:33:44Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>dagger-dsl-processor/src/main/kotlin/mappers.kt (2)</summary><blockquote>

`5-7`: **Clean interface definition with clear responsibility.**

The interface is well-designed with a single, focused method. Consider adding KDoc comments to document the purpose and behavior of this interface.


```diff
+/**
+ * Maps a Component instance to a TypeSpec representation for code generation.
+ */
 interface ComponentToFileSpecMapper {
+    /**
+     * Creates a TypeSpec from the given Component.
+     *
+     * @param component The component to be mapped to a file specification
+     * @return A TypeSpec representing the Kotlin interface for the component
+     */
     fun map(component: Component): TypeSpec
 }
```

---

`9-17`: **Implementation looks good with proper annotation handling.**

The implementation correctly maps a Component to a TypeSpec representing an interface with the Dagger component annotation. The code is using the fully qualified reference to `dagger.Component`, which resolves the ambiguity mentioned in the previous review.


Consider making this implementation more extensible for future needs:

```diff
 class ComponentToFileSpecMapperImpl : ComponentToFileSpecMapper {
+    /**
+     * Maps a Component to a TypeSpec representing a Dagger component interface.
+     *
+     * @param component The component to be mapped
+     * @return A TypeSpec representing the generated interface
+     */
     override fun map(component: Component): TypeSpec {
         val generatedClass =
             TypeSpec.interfaceBuilder(component.name)
                 .addAnnotation(ClassName(dagger.Component::class.java.packageName, dagger.Component::class.java.simpleName))
+                // Add any modules or dependencies based on component configuration
                 .build()
         return generatedClass
     }
+    
+    // Additional private helper methods can be added here as the mapping logic grows
 }
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 03c7ea3294d18892324f17cb620aef985035b14e and b382f636a1b86267bb0ea946c178e6a2395243d2.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `dagger-dsl-processor/src/main/kotlin/mappers.kt` (1 hunks)

</details>

<details>
<summary>🔇 Additional comments (1)</summary><blockquote>

<details>
<summary>dagger-dsl-processor/src/main/kotlin/mappers.kt (1)</summary>

`1-4`: **Good choice of imports.**

The imports are correctly focused on just the necessary components for the mapping functionality.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T18:50:59Z

Review comments:
diff_hunk: @@ -0,0 +1,18 @@
+import com.squareup.kotlinpoet.ClassName
+import com.squareup.kotlinpoet.TypeSpec
+import dagger.dsl.core.Component
+
+interface ComponentToFileSpecMapper {
+    fun map(component: Component): TypeSpec
+}
+
+class ComponentToFileSpecMapperImpl : ComponentToFileSpecMapper {
+    override fun map(component: Component): TypeSpec {
+        val generatedClass =
+            TypeSpec.interfaceBuilder(component.name)
+                .addAnnotation(ClassName(dagger.Component::class.java.packageName, Component::class.java.simpleName))
+                .build()
+
path: dagger-dsl-processor/src/main/kotlin/mappers.kt
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Fix potential annotation reference confusion.**

The current implementation might be using the wrong class reference for the annotation. The code appears to be referencing `Component::class.java.simpleName` after importing `dagger.dsl.core.Component`, which could cause confusion.


```diff
val generatedClass =
    TypeSpec.interfaceBuilder(component.name)
-        .addAnnotation(ClassName(dagger.Component::class.java.packageName, Component::class.java.simpleName))
+        .addAnnotation(ClassName(dagger.Component::class.java.packageName, dagger.Component::class.java.simpleName))
        .build()
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        val generatedClass =
            TypeSpec.interfaceBuilder(component.name)
                .addAnnotation(ClassName(dagger.Component::class.java.packageName, dagger.Component::class.java.simpleName))
                .build()
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-01T18:33:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+package usescases.component
+
+import ComponentToFileSpecMapper
+import ComponentToFileSpecMapperImpl
path: dagger-dsl-processor/src/test/kotlin/MappersTest.kt
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Use fully qualified imports.**

The imports for `ComponentToFileSpecMapper` and `ComponentToFileSpecMapperImpl` don't include package names. This could lead to confusion if there are multiple classes with the same name.


```diff
- import ComponentToFileSpecMapper
- import ComponentToFileSpecMapperImpl
+ import com.example.ComponentToFileSpecMapper
+ import com.example.ComponentToFileSpecMapperImpl
```

Replace `com.example` with the actual package where these classes are defined.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
import com.example.ComponentToFileSpecMapper
import com.example.ComponentToFileSpecMapperImpl
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-01T18:33:43Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-01T18:28:28Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
The pull request enhances type safety by making the `name` property in both the `ComponentBuilder` and `Component` non-nullable with a default value. It introduces new functionality with a mapper interface to translate components into Kotlin file specifications and a writer interface for dynamic code generation. Additionally, the build configuration has been updated to include the KSP plugin and several new dependencies, with corresponding version references added. New tests have been provided to validate the functionality of both the mapper and the writer.

## Changes

| File(s)                                                                                           | Change Summary                                                                                                                                                                                                                                                                       |
|---------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `dagger-dsl-core/.../dsl.kt`                                                                       | Updated `ComponentBuilder` and `Component` by changing the `name` property from a nullable type to a non-nullable type with a default value of `"component"`.                                                                                                                 |
| `dagger-dsl-processor/build.gradle.kts`<br/>`gradle/libs.versions.toml`                             | Added the KSP plugin and new dependencies: `kotlinPoet`, `dagger`, `mockk`, and `code-factory`, along with their version references.                                                                                                                                                |
| `dagger-dsl-processor/src/main/kotlin/mappers.kt`                                                  | Introduced a new interface `ComponentToFileSpecMapper` and its implementation `ComponentToFileSpecMapperImpl` for mapping components to Kotlin `TypeSpec` objects with an appropriate Dagger annotation.                                                                     |
| `dagger-dsl-processor/src/main/kotlin/usescases/Writer.kt`                                         | Added a new `Writer` interface and its implementation `WriterImpl` for generating Kotlin files. The writer uses a `CodeGenerator` to create files with a hardcoded filename ("Di.kt") and writes formatted Kotlin code.                                                     |
| `dagger-dsl-processor/src/test/kotlin/MappersTest.kt`<br/>`dagger-dsl-processor/src/test/kotlin/WriterTest.kt` | Added new test classes for verifying the functionality of the mapper (`MappersTest`) and the writer (`WriterTest`) implementations using the Kotest framework.                                                                                                                   |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant C as Component
    participant M as ComponentToFileSpecMapperImpl
    participant T as TypeSpec
    C->>M: map(component)
    Note right of M: Build TypeSpec using component name and @dagger.Component annotation
    M->>T: Return constructed TypeSpec
```

```mermaid
sequenceDiagram
    participant W as WriterImpl
    participant G as CodeGenerator
    participant FS as File System
    W->>G: createNewFile(packageName, "Di.kt")
    G->>FS: Generate file with dependencies
    W->>FS: Write formatted Kotlin code (package and component info)
```

## Poem
> I'm but a rabbit in the code-night,  
> Hopping through non-null fields so bright.  
> Mappers and writers craft magic with care,  
> New plugins and tests now dancing in air.  
> Each line of code makes my heart beat with glee,  
> A bunny’s delight in this change spree! 🐰  
> Leap on, developers, and let the code run free!

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Docstrings were successfully generated. (🔄  Check again to generate docstrings again)

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=AntonButov/dagger-dsl&utm_content=13):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: coderabbitai[bot]
created_at: 2025-04-01T19:00:36Z
body: > [!NOTE]
> Generated docstrings for this pull request at https://github.com/AntonButov/dagger-dsl/pull/17
author_association: CONTRIBUTOR