Multiple factories

@DIFactory is repeatable. Annotating one object several times builds several related classes, each annotation generating its own function, all in one file named after the object:

class LoginScreen(val heading: String)
class HomeScreen(val heading: String, val count: Int)

@DIFactory(builds = LoginScreen::class, from = ScreenModule::class)
@DIFactory(builds = HomeScreen::class, from = ScreenModule::class)
object ScreensFactory {
    internal fun ScreenModule.argHeading(): String = "Welcome to $appName" (1)
}
1 Shared by both factories.
InaraScreensFactory.kt
public fun ScreensFactory.LoginScreen(module: ScreenModule): LoginScreen = ...
public fun ScreensFactory.HomeScreen(module: ScreenModule): HomeScreen = ...

Shared arg<Argument> functions

An arg<Argument> function serves every annotation whose from is its receiver, and whose selected constructor has a parameter with the matching name. Above, argHeading resolves heading for both screens.

An arg<Argument> function that serves none of the annotations is a compile error.

Per-annotation options

with, withNullable, suspend and constructorIndex are set per annotation. A single object can, for example, generate a suspend function next to a regular one, or build the same class from two different modules:

@DIFactory(builds = Profile::class, from = OfflineModule::class)
@DIFactory(builds = Profile::class, from = SessionModule::class, suspend = DIFactory.Suspend.Force)
object ProfileFactory

Conflicting annotations

Two annotations that would generate the same signature are a compile error. The signature is made of the builds class, the from module, the with type, and the types of the pass-through parameters.

Two annotations that only differ by constructorIndex are therefore valid, as long as the selected constructors leave different arguments to pass through.

Grouping the factories of a feature in one object keeps its wiring in one place, and lets them share their arg<Argument> functions.