diff --git a/README.md b/README.md
index 4a99a319..907c3020 100644
--- a/README.md
+++ b/README.md
@@ -109,9 +109,9 @@ project-dep type checks + content layout rules from live validators
| Supported target types | implemented | purpose | validation |
|:----------------------:|:-----------:|:-------:|:----------:|
-| `androidBinary` | ✅ | Generate single APK | name + no `res/`; project deps **unrestricted** (`EmptyValidator`) |
-| `androidApp` | ✅ | Application / root Android library | name + no `res/`; project deps **unrestricted** |
-| `androidLibrary` | ✅ | Android library | name only; project deps **unrestricted** |
+| `androidBinary` | ✅ | Generate single APK | name + no `res/`; composition-root project-dep list |
+| `androidApp` | ✅ | Application / root Android library | name + no `res/`; composition-root project-dep list |
+| `androidLibrary` | ✅ | Android library | name + project-dep list (**no** `impl`) |
| `uiLibrary` | ✅ | Shared UI library for impl/widget | project-dep list |
| `widget` | ✅ | Custom View / UI component | project-dep list |
| `androidRes` | ✅ | Resources only | only `res/` under `src/main` + project-dep list |
@@ -137,7 +137,7 @@ That document is generated from each target’s
| `api` | `api`, `library` |
| `impl` | `api`, `android-util`, `test-util`, `util`, `library`, `ui-library`, `res`, `viewbinding`, `widget` |
| `library` (JVM) | `util`, `test-util` |
-| `androidLibrary` | *any* (`EmptyValidator`) |
+| `androidLibrary` | `library`, `util`, `android-util`, `test-util`, `res`, `api` |
| `uiLibrary` | `widget`, `util`, `android-util`, `res` |
| `util` | `util`, `library` |
| `androidUtil` | `android-util`, `test-util`, `res` |
@@ -146,11 +146,11 @@ That document is generated from each target’s
| `androidRes` | `res`, `widget` |
| `widget` | `ui-library`, `widget`, `util`, `android-util`, `res` |
| `viewBinding` | `api`, `widget`, `res`, `library`, `android-util` |
-| `androidApp` / `androidBinary` | *any* (`EmptyValidator`) |
+| `androidApp` | `api`, `impl`, `library`, `util`, `android-util`, `test-util`, `res`, `viewbinding`, `widget`, `ui-library` |
+| `androidBinary` | `app`, `api`, `impl`, `library`, `util`, `android-util`, `test-util`, `res`, `viewbinding`, `widget`, `ui-library` |
| `androidNative` | *(no project-dep check)* |
-Tightening unrestricted entry targets and Dagger-friendly `api`/`impl`
-boundaries is tracked as **F-011**.
+Dagger2-friendly `api`/`impl` + composition roots: **F-011** (landed).
Icons made by Freepik
from www.flaticon.com
diff --git a/TICKETS.md b/TICKETS.md
index 9e7fe771..05fc515b 100644
--- a/TICKETS.md
+++ b/TICKETS.md
@@ -18,7 +18,7 @@ Update this file when picking or finishing work. Cron workers must pick the **hi
| ID | Status | Title | Notes |
|----|--------|-------|-------|
| F-010 | done | Document strict dependency matrix from live code (not only README) | `docs/DEPENDENCY-MATRIX.md` + README summary aligned to validators |
-| F-011 | todo | Tighten validation for `api` / `impl` (Dagger2-friendly boundaries) | Align with current types; related GH #56, #18 |
+| F-011 | done | Tighten validation for `api` / `impl` (Dagger2-friendly boundaries) | app/binary/androidLibrary no longer EmptyValidator; impl still no→impl; docs matrix updated |
| F-012 | todo | External deps catalog UX + tooling polish | `plugins/deps` catalog generators |
| F-013 | todo | Compose support for Android library/ui targets | GH #96 |
| F-014 | todo | Sample app: gold-standard multi-feature structure | Home/characters already present; modernize |
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index 5d6fcdfd..126f487e 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -139,7 +139,7 @@ when validators change.
| `api` | `api`, `library` | no `res/` under `src/main` |
| `impl` | `api`, `android-util`, `test-util`, `util`, `library`, `ui-library`, `res`, `viewbinding`, `widget` | — |
| `library` (JVM) | `util`, `test-util` | — |
-| `androidLibrary` | **EmptyValidator** (any project) | — |
+| `androidLibrary` | `library`, `util`, `android-util`, `test-util`, `res`, `api` | — |
| `uiLibrary` | `widget`, `util`, `android-util`, `res` | — |
| `util` | `util`, `library` | no `res/` |
| `androidUtil` | `android-util`, `test-util`, `res` | no `res/` |
@@ -148,14 +148,14 @@ when validators change.
| `androidRes` | `res`, `widget` | **only** `res/` under `src/main` |
| `widget` | `ui-library`, `widget`, `util`, `android-util`, `res` | — |
| `viewBinding` | `api`, `widget`, `res`, `library`, `android-util` | only `layout*` under `src/main/res` |
-| `androidApp` | **EmptyValidator** | no `res/` |
-| `androidBinary` | **EmptyValidator** | no `res/` |
+| `androidApp` | `api`, `impl`, `library`, `util`, `android-util`, `test-util`, `res`, `viewbinding`, `widget`, `ui-library` | no `res/` |
+| `androidBinary` | `app`, `api`, `impl`, `library`, `util`, `android-util`, `test-util`, `res`, `viewbinding`, `widget`, `ui-library` | no `res/` |
| `androidNative` | (no `applyDependencies` in current code) | no `res/` |
Notes for later tickets:
-- `impl` cannot depend on other `impl` (good for Dagger-ish boundaries) — F-011.
-- `androidLibrary` / `androidApp` / `androidBinary` skip dep-type checks — partial validation in README sense.
+- `impl` cannot depend on other `impl` (Dagger-friendly) — enforced; F-011.
+- `androidLibrary` / `androidApp` / `androidBinary` use restricted project-dep lists — F-011 done.
- JVM `library` and Android `androidLibrary` share `LibraryTargetTemplate` suffix `library` — naming collision risk for forma-core registry design (F-020).
### 2.3 Feature stack (Android module)
@@ -313,7 +313,7 @@ Suggested extraction order (tickets F-020…F-024):
| Item | Ticket |
|------|--------|
| ~~README dependency matrix ≠ live validators~~ → [`docs/DEPENDENCY-MATRIX.md`](DEPENDENCY-MATRIX.md) | F-010 done |
-| `EmptyValidator` on app/binary/androidLibrary | F-011 |
+| ~~`EmptyValidator` on app/binary/androidLibrary~~ (composition-root + library allowlists) | F-011 done |
| ~~AGP 7.4.2 compile vs 8.1.2 runtime~~ (aligned 8.1.2) | F-003 done |
| ~~CI missing SDK + Java on some jobs~~ (GHA green on PR #153) | F-004 done |
| Compose flag in settings, limited target support | F-013 |
diff --git a/docs/DEPENDENCY-MATRIX.md b/docs/DEPENDENCY-MATRIX.md
index 26aac42a..ea80540d 100644
--- a/docs/DEPENDENCY-MATRIX.md
+++ b/docs/DEPENDENCY-MATRIX.md
@@ -8,7 +8,7 @@ Source of truth for **F-010**. Every rule below is taken from the live
When validators change, update **this file first**, then the README summary
matrix. Do not invent rules from aspirational docs.
-Last verified: **2026-07-11** against `v2` tip (post F-003 / F-004).
+Last verified: **2026-07-11** against `v2` tip + F-011 validator tighten.
---
@@ -76,7 +76,7 @@ these suffixes (or are unrestricted if `EmptyValidator`).
| `api` | `api.kt` | `validator(api, library)` | `api`, `library` |
| `impl` | `impl.kt` | `validator(api, android-util, test-util, util, library, ui-library, res, viewbinding, widget)` | `api`, `android-util`, `test-util`, `util`, `library`, `ui-library`, `res`, `viewbinding`, `widget` |
| `library` (JVM) | `library.kt` | `validator(util, test-util)` | `util`, `test-util` |
-| `androidLibrary` | `androidLibrary.kt` | **`EmptyValidator`** | *any project* |
+| `androidLibrary` | `androidLibrary.kt` | `validator(library, util, android-util, test-util, res, api)` | `library`, `util`, `android-util`, `test-util`, `res`, `api` |
| `uiLibrary` | `uiLibrary.kt` | `validator(widget, util, android-util, res)` | `widget`, `util`, `android-util`, `res` |
| `util` | `util.kt` | `validator(util, library)` | `util`, `library` |
| `androidUtil` | `androidUtil.kt` | `validator(android-util, test-util, res)` | `android-util`, `test-util`, `res` |
@@ -85,21 +85,25 @@ these suffixes (or are unrestricted if `EmptyValidator`).
| `androidRes` | `androidRes.kt` | `validator(res, widget)` | `res`, `widget` |
| `widget` | `widget.kt` | `validator(ui-library, widget, util, android-util, res)` | `ui-library`, `widget`, `util`, `android-util`, `res` |
| `viewBinding` | `viewBinding.kt` | `validator(api, widget, res, library, android-util)` | `api`, `widget`, `res`, `library`, `android-util` |
-| `androidApp` | `androidApp.kt` | **`EmptyValidator`** | *any project* |
-| `androidBinary` | `androidBinary.kt` | **`EmptyValidator`** | *any project* |
+| `androidApp` | `androidApp.kt` | `validator(api, impl, library, util, android-util, test-util, res, viewbinding, widget, ui-library)` | `api`, `impl`, `library`, `util`, `android-util`, `test-util`, `res`, `viewbinding`, `widget`, `ui-library` |
+| `androidBinary` | `androidBinary.kt` | `validator(app, api, impl, library, util, android-util, test-util, res, viewbinding, widget, ui-library)` | `app`, `api`, `impl`, `library`, `util`, `android-util`, `test-util`, `res`, `viewbinding`, `widget`, `ui-library` |
| `androidNative` | `androidNative.kt` | *(no `applyDependencies`)* | *no project-dep validation* |
### Explicit non-edges (important product rules)
These follow from the table (not from separate deny-lists):
-- **`impl` cannot depend on `impl`** — only listed suffixes; good for
- Dagger-style feature boundaries (tighten further in F-011).
+- **`impl` cannot depend on `impl`** — only listed suffixes; Dagger-style feature
+ boundaries (implementations compose only at app/binary).
- **`api` cannot depend on `impl` / widgets / res / viewbinding** — JVM API
surface only (`api` + `library`).
- **`library` (JVM) cannot depend on `api` / `impl`** — comment in code:
“Can't depend on api\impl”.
- **`util` cannot depend on `api` / `impl`** — same intent as library.
+- **`androidLibrary` cannot depend on `impl` / widgets / viewbinding** —
+ shared libs may use `api` contracts only (F-011).
+- **`androidApp` / `androidBinary` cannot depend on other `binary`** —
+ single APK composition root (F-011; `app` may not depend on `app`/`binary`).
- **Circular-ish UI graph is intentional while experimental:** `uiLibrary`
may depend on `widget`, and `widget` may depend on `ui-library`
(`uiLibrary.kt` comment).
@@ -142,7 +146,7 @@ Rows = **consumer**. Columns = **dependency type (suffix)**.
| **api** | Y | — | Y | — | — | — | — | — | — | — | — | — | — | — |
| **impl** | Y | — | Y | Y | Y | Y | Y | — | Y | Y | Y | — | — | — |
| **library** (JVM) | — | — | — | — | Y | Y | — | — | — | — | — | — | — | — |
-| **androidLibrary** | * | * | * | * | * | * | * | * | * | * | * | * | * | * |
+| **androidLibrary** | Y | — | Y | — | Y | Y | Y | — | Y | — | — | — | — | — |
| **uiLibrary** | — | — | — | — | Y | — | Y | — | Y | — | Y | — | — | — |
| **util** | — | — | Y | — | Y | — | — | — | — | — | — | — | — | — |
| **androidUtil** | — | — | — | — | — | Y | Y | — | Y | — | — | — | — | — |
@@ -151,8 +155,8 @@ Rows = **consumer**. Columns = **dependency type (suffix)**.
| **androidRes** | — | — | — | — | — | — | — | — | Y | — | Y | — | — | — |
| **widget** | — | — | — | Y | Y | — | Y | — | Y | — | Y | — | — | — |
| **viewBinding** | Y | — | Y | — | — | — | Y | — | Y | — | Y | — | — | — |
-| **androidApp** | * | * | * | * | * | * | * | * | * | * | * | * | * | * |
-| **androidBinary** | * | * | * | * | * | * | * | * | * | * | * | * | * | * |
+| **androidApp** | Y | Y | Y | Y | Y | Y | Y | — | Y | Y | Y | — | — | — |
+| **androidBinary** | Y | Y | Y | Y | Y | Y | Y | — | Y | Y | Y | Y | — | — |
| **androidNative** | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a |
Self-deps: a type may depend on itself only if its own suffix is in its
@@ -171,8 +175,8 @@ Notable mismatches fixed by treating **this document** as truth:
| Topic | Old README implication | Live code |
|-------|------------------------|-----------|
-| `androidLibrary` project deps | selective ✅/❌ grid | **`EmptyValidator`** (unrestricted) |
-| `androidApp` / `androidBinary` project deps | selective grid | **`EmptyValidator`** |
+| `androidLibrary` project deps | selective ✅/❌ grid | **restricted** (no `impl`/widget/viewbinding) after F-011 |
+| `androidApp` / `androidBinary` project deps | selective grid | **restricted** composition-root lists after F-011 |
| `impl` → `impl` | ❌ (agrees) | not in allowed list |
| `api` → `library` | not clearly shown | **allowed** |
| `impl` → `ui-library` / `viewbinding` / `widget` / `res` | partially missing | **allowed** |
@@ -181,8 +185,7 @@ Notable mismatches fixed by treating **this document** as truth:
| `uiLibrary` | missing / confused with library | full row above |
| DSL names | `androidWidget`, `utils`, … | `widget`, `util`, … |
-Tightening `EmptyValidator` targets and Dagger-friendly `api`/`impl` edges is
-**F-011**, not documentation fiction.
+Tightening unrestricted entry targets landed in **F-011**.
---
@@ -193,7 +196,7 @@ Tightening `EmptyValidator` targets and Dagger-friendly `api`/`impl` edges is
- `feature/*/api` → JVM `api`
- `feature/*/impl` → Android `impl` + viewbinding/res/widget/core libraries
- `binary` → `androidBinary` with explicit deps on root-app + feature api/impl
- (legal today because binary uses `EmptyValidator`)
+ (legal under composition-root allowlist; F-011)
See `docs/ARCHITECTURE.md` §2.2 and §3 for the module map.
@@ -206,5 +209,5 @@ See `docs/ARCHITECTURE.md` §2.2 and §3 for the module map.
3. Refresh the compact README matrix (link here as canonical).
4. Note the change in `docs/PROGRESS.md` / ticket notes when user-facing.
-Related tickets: **F-011** (tighten validation), **F-020** (forma-core type
+Related tickets: **F-012** (deps catalog UX), **F-020** (forma-core type
registry / shared `library` suffix).
diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md
index 9d5b7a40..d25358d4 100644
--- a/docs/PROGRESS.md
+++ b/docs/PROGRESS.md
@@ -2,27 +2,34 @@
Newest entries first.
+## 2026-07-11 — F-011 api/impl + composition-root validation
+
+- **Ticket:** F-011 → `done`
+- **Branch:** `forma/F-011-api-impl-validation`
+- **Code:**
+ - `androidApp` / `androidBinary` / `androidLibrary`: replace `EmptyValidator` with Dagger-friendly project-dep allowlists
+ - `androidLibrary` **cannot** depend on `impl` (or widget/viewbinding)
+ - `impl` still cannot depend on `impl`; KDoc on `api`/`impl` documents boundaries
+ - Clearer validation error text in `Validator.kt`
+- **Docs:** `docs/DEPENDENCY-MATRIX.md`, README summary, TICKETS
+- **Verify:** `plugins` + `application` `./gradlew build` (see commit/PR notes)
+- **Next:** F-012 external deps catalog UX
+
## 2026-07-11 — F-010 Dependency matrix from live validators
- **Ticket:** F-010 → `done`
- **Branch:** `forma/F-010-dependency-matrix` (from `origin/v2` after F-003/F-004 merge)
- **Actions:**
- - Added `docs/DEPENDENCY-MATRIX.md` as canonical code-truth matrix:
- - How name / project-dep / content validation works
- - Per-DSL allowed suffixes from each `applyDependencies(validator=…)`
- - Content rules (`disallowResources` / `onlyAllowResources` / `onlyAllowLayouts`)
- - Full consumer×dependency table (Y / * / — / n/a)
- - README vs code divergence notes
- - Replaced aspirational README ✅/❌ grid with code-aligned summary + link
- - Expanded Progress target table (`uiLibrary`, `viewBinding`, `androidNative`, real DSL names)
- - Pointed `docs/ARCHITECTURE.md` §2.2 + §7 at the new doc; marked F-010 done
-- **Also this run (P0 land on `v2`):**
- - Squash-merge path unavailable (repo allows squash only); merged #152 then #153 into `v2` locally and pushed (`123ec44`)
- - PR #152 F-003 and #153 F-004 both **MERGED** into `v2`
-- **Build:** docs-only slice; no Gradle re-run required for matrix extraction (rules read from Kotlin sources)
-- **Commits/PRs:** this branch → PR base `v2`
-- **Blockers:** none
-- **Next step:** F-011 tighten `api`/`impl` (+ optional replace `EmptyValidator` on app/binary/androidLibrary)
+ - Added `docs/DEPENDENCY-MATRIX.md` as canonical code-truth matrix
+ - Replaced aspirational README matrix with code-aligned summary
+ - Pointed `docs/ARCHITECTURE.md` at the new doc; marked F-010 done
+- **Also that run:** F-003 #152 and F-004 #153 merged into `v2` (`123ec44`)
+- **PR:** #154 squash-merged to `v2` as `619ce05`
+
+## 2026-07-11 — v2 base of operations (merge open PRs)
+
+- Created `v2` from `master`; integrated F-001/F-002; workers branch/PR against `v2`
+- Tip later advanced with F-003/F-004/F-010/F-011
## 2026-07-11 — F-004 CI green (workflow + badge)
diff --git a/plugins/android/src/main/java/androidApp.kt b/plugins/android/src/main/java/androidApp.kt
index bec76d4a..bb2b98fa 100644
--- a/plugins/android/src/main/java/androidApp.kt
+++ b/plugins/android/src/main/java/androidApp.kt
@@ -2,13 +2,23 @@ import tools.forma.android.feature.AndroidLibraryFeatureConfiguration
import tools.forma.android.feature.androidLibraryFeatureDefinition
import tools.forma.android.feature.applyFeatures
import tools.forma.android.feature.kotlinAndroidFeatureDefinition
+import tools.forma.android.target.AndroidUtilTargetTemplate
+import tools.forma.android.target.ApiTargetTemplate
import tools.forma.android.target.ApplicationTargetTemplate
+import tools.forma.android.target.ImplTargetTemplate
+import tools.forma.android.target.LibraryTargetTemplate
+import tools.forma.android.target.ResourcesTargetTemplate
+import tools.forma.android.target.TestUtilTargetTemplate
+import tools.forma.android.target.UiLibraryTargetTemplate
+import tools.forma.android.target.UtilTargetTemplate
+import tools.forma.android.target.ViewBindingTargetTemplate
+import tools.forma.android.target.WidgetTargetTemplate
import tools.forma.owners.NoOwner
import tools.forma.owners.Owner
import tools.forma.android.utils.BuildConfiguration
-import tools.forma.validation.EmptyValidator
import tools.forma.android.validation.disallowResources
import tools.forma.validation.validate
+import tools.forma.validation.validator
import tools.forma.android.visibility.Public
import tools.forma.android.visibility.Visibility
import tools.forma.deps.core.FormaDependency
@@ -18,7 +28,11 @@ import org.gradle.api.Project
import tools.forma.android.feature.kaptConfigurationFeature
/**
- * TODO Can't depend on widgets, cant depend on databindings
+ * Root Android application library (feature composition, not the APK entry).
+ *
+ * Project-deps allowlist is Dagger2-friendly: may wire feature [api]/[impl],
+ * shared libraries/utils, and UI building blocks. Cannot depend on other `app`
+ * or `binary` targets (composition stays single-rooted via [androidBinary]).
*/
fun Project.androidApp(
packageName: String,
@@ -48,9 +62,19 @@ fun Project.androidApp(
kotlinAndroidFeatureDefinition()
)
-
applyDependencies(
- validator = EmptyValidator,
+ validator = validator(
+ ApiTargetTemplate,
+ ImplTargetTemplate,
+ LibraryTargetTemplate,
+ UtilTargetTemplate,
+ AndroidUtilTargetTemplate,
+ TestUtilTargetTemplate,
+ ResourcesTargetTemplate,
+ ViewBindingTargetTemplate,
+ WidgetTargetTemplate,
+ UiLibraryTargetTemplate,
+ ),
dependencies = dependencies,
repositoriesConfiguration = Forma.settings.repositories,
testDependencies = testDependencies,
@@ -58,4 +82,3 @@ fun Project.androidApp(
configurationFeatures = kaptConfigurationFeature()
)
}
-
diff --git a/plugins/android/src/main/java/androidBinary.kt b/plugins/android/src/main/java/androidBinary.kt
index e09601bc..ab9ea451 100644
--- a/plugins/android/src/main/java/androidBinary.kt
+++ b/plugins/android/src/main/java/androidBinary.kt
@@ -4,27 +4,39 @@ import tools.forma.android.feature.androidBinaryFeatureDefinition
import tools.forma.android.feature.applyFeatures
import tools.forma.owners.NoOwner
import tools.forma.owners.Owner
+import tools.forma.android.target.AndroidUtilTargetTemplate
+import tools.forma.android.target.ApiTargetTemplate
+import tools.forma.android.target.ApplicationTargetTemplate
import tools.forma.android.target.BinaryTargetTemplate
+import tools.forma.android.target.ImplTargetTemplate
+import tools.forma.android.target.LibraryTargetTemplate
+import tools.forma.android.target.ResourcesTargetTemplate
+import tools.forma.android.target.TestUtilTargetTemplate
+import tools.forma.android.target.UiLibraryTargetTemplate
+import tools.forma.android.target.UtilTargetTemplate
+import tools.forma.android.target.ViewBindingTargetTemplate
+import tools.forma.android.target.WidgetTargetTemplate
import tools.forma.android.utils.BuildConfiguration
import tools.forma.android.validation.disallowResources
import tools.forma.deps.core.FormaDependency
import tools.forma.deps.core.applyDependencies
-import tools.forma.validation.EmptyValidator
import tools.forma.validation.validate
+import tools.forma.validation.validator
/**
- * Android Binary target - application entry point.
+ * Android Binary target — application entry point (single APK).
*
- * Manifest + minimal set of resources + root android project dependency only.
- * No library dependencies, no source code.
+ * Composition root for Dagger graphs: may depend on root [androidApp], feature
+ * [api]/[impl], and shared libraries/utils. Project-dep types are restricted
+ * (no longer [tools.forma.validation.EmptyValidator]).
*
- * @param packageName - Application package name, used for publishing
- * @param owner - owner of the target, team responsible for maintenance
- * @param dependencies - list of external and project dependencies for the target
- * @param buildConfiguration - Android Gradle Plugin configuration DSL
- * @param testInstrumentationRunner - class name used for instrumentation tests execution
- * @param consumerMinificationFiles - Proguard/R8 minification files list
- * @param manifestPlaceholders - placeholders ot be injected in manifest
+ * @param packageName Application package name, used for publishing
+ * @param owner owner of the target, team responsible for maintenance
+ * @param dependencies list of external and project dependencies for the target
+ * @param buildConfiguration Android Gradle Plugin configuration DSL
+ * @param testInstrumentationRunner class name used for instrumentation tests execution
+ * @param consumerMinificationFiles Proguard/R8 minification files list
+ * @param manifestPlaceholders placeholders to be injected in manifest
*/
fun Project.androidBinary(
packageName: String,
@@ -56,11 +68,22 @@ fun Project.androidBinary(
)
applyDependencies(
- validator = EmptyValidator,
+ validator = validator(
+ ApplicationTargetTemplate,
+ ApiTargetTemplate,
+ ImplTargetTemplate,
+ LibraryTargetTemplate,
+ UtilTargetTemplate,
+ AndroidUtilTargetTemplate,
+ TestUtilTargetTemplate,
+ ResourcesTargetTemplate,
+ ViewBindingTargetTemplate,
+ WidgetTargetTemplate,
+ UiLibraryTargetTemplate,
+ ),
dependencies = dependencies,
repositoriesConfiguration = Forma.settings.repositories
)
return TargetBuilder(this)
}
-
diff --git a/plugins/android/src/main/java/androidLibrary.kt b/plugins/android/src/main/java/androidLibrary.kt
index 6e01a6c2..31039256 100644
--- a/plugins/android/src/main/java/androidLibrary.kt
+++ b/plugins/android/src/main/java/androidLibrary.kt
@@ -1,7 +1,4 @@
import org.gradle.api.Project
-import org.gradle.api.artifacts.type.ArtifactTypeDefinition
-import org.gradle.api.internal.artifacts.ArtifactAttributes.ARTIFACT_FORMAT
-import org.gradle.kotlin.dsl.dependencies
import tools.forma.android.feature.AndroidLibraryFeatureConfiguration
import tools.forma.android.feature.androidLibraryFeatureDefinition
import tools.forma.android.feature.applyFeatures
@@ -9,18 +6,28 @@ import tools.forma.android.feature.kaptConfigurationFeature
import tools.forma.android.feature.kotlinAndroidFeatureDefinition
import tools.forma.owners.NoOwner
import tools.forma.owners.Owner
+import tools.forma.android.target.AndroidUtilTargetTemplate
+import tools.forma.android.target.ApiTargetTemplate
import tools.forma.android.target.LibraryTargetTemplate
+import tools.forma.android.target.ResourcesTargetTemplate
+import tools.forma.android.target.TestUtilTargetTemplate
+import tools.forma.android.target.UtilTargetTemplate
import tools.forma.android.utils.BuildConfiguration
import tools.forma.android.visibility.Public
import tools.forma.android.visibility.Visibility
import tools.forma.deps.core.FormaDependency
import tools.forma.deps.core.NamedDependency
import tools.forma.deps.core.applyDependencies
-import tools.forma.validation.EmptyValidator
import tools.forma.validation.validate
+import tools.forma.validation.validator
/**
- * TODO Can't depend on widgets, cant depend on databindings
+ * Shared Android library (not a feature [impl]).
+ *
+ * Dagger-friendly: may depend on other libraries/utils/res and feature [api]
+ * contracts, but **not** on [impl] (implementations are composed only at
+ * [androidApp] / [androidBinary]). Also disallows widgets/viewbinding as
+ * project deps (use dedicated targets).
*/
fun Project.androidLibrary(
packageName: String,
@@ -48,7 +55,14 @@ fun Project.androidLibrary(
)
applyDependencies(
- validator = EmptyValidator,
+ validator = validator(
+ LibraryTargetTemplate,
+ UtilTargetTemplate,
+ AndroidUtilTargetTemplate,
+ TestUtilTargetTemplate,
+ ResourcesTargetTemplate,
+ ApiTargetTemplate,
+ ),
dependencies = dependencies,
testDependencies = testDependencies,
androidTestDependencies = androidTestDependencies,
@@ -58,4 +72,3 @@ fun Project.androidLibrary(
return TargetBuilder(this)
}
-
diff --git a/plugins/android/src/main/java/api.kt b/plugins/android/src/main/java/api.kt
index 6c4b0530..f353c9b5 100644
--- a/plugins/android/src/main/java/api.kt
+++ b/plugins/android/src/main/java/api.kt
@@ -11,6 +11,13 @@ import tools.forma.deps.core.applyDependencies
import tools.forma.deps.core.FormaDependency
import tools.forma.validation.validate
+/**
+ * Feature **API** surface (JVM). Dagger2-friendly public contracts only.
+ *
+ * May depend on other `api` and pure `library` modules. Must not depend on
+ * `impl`, Android UI (`widget` / `viewbinding` / `res`), or utils that pull
+ * Android into the contract layer.
+ */
fun Project.api(
packageName: String,
owner: Owner = NoOwner,
@@ -29,4 +36,3 @@ fun Project.api(
repositoriesConfiguration = Forma.settings.repositories
)
}
-
diff --git a/plugins/android/src/main/java/impl.kt b/plugins/android/src/main/java/impl.kt
index d468e08e..00f1ccfc 100644
--- a/plugins/android/src/main/java/impl.kt
+++ b/plugins/android/src/main/java/impl.kt
@@ -21,6 +21,15 @@ import tools.forma.deps.core.applyDependencies
import tools.forma.validation.validate
import tools.forma.validation.validator
+/**
+ * Feature **implementation** (Android library + optional view binding / kapt).
+ *
+ * Dagger2-friendly boundaries:
+ * - **May** depend on feature `api` contracts, shared libraries/utils, and UI
+ * building blocks (`res`, `viewbinding`, `widget`, `ui-library`).
+ * - **Must not** depend on other `impl` modules — feature graphs compose only
+ * at [androidApp] / [androidBinary] so implementations stay independent.
+ */
fun Project.impl(
packageName: String,
dependencies: FormaDependency = emptyDependency(),
@@ -67,4 +76,3 @@ fun Project.impl(
configurationFeatures = kaptConfigurationFeature()
)
}
-
diff --git a/plugins/validation/src/main/java/tools/forma/validation/Validator.kt b/plugins/validation/src/main/java/tools/forma/validation/Validator.kt
index d4f8decd..9fc6db8f 100644
--- a/plugins/validation/src/main/java/tools/forma/validation/Validator.kt
+++ b/plugins/validation/src/main/java/tools/forma/validation/Validator.kt
@@ -43,8 +43,9 @@ fun throwProjectValidationError(
) {
throw ProjectValidationError(
"""
- Project ${name}: name does not match type requirements
- Projects of type "${targets.joinToString { it::class.simpleName ?: "" }} should contain name suffix from the list: "${targets.joinToString { it.suffix }}"
+ Project $name: name does not match allowed target type(s)
+ Allowed name suffix(es): ${targets.joinToString { it.suffix }}
+ (Used for self-type checks and project-dependency type checks.)
""".trimIndent()
)
}