Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand All @@ -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` |
Expand All @@ -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 <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a>
from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
2 changes: 1 addition & 1 deletion TICKETS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
12 changes: 6 additions & 6 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/` |
Expand All @@ -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 checkspartial validation in README sense.
- `impl` cannot depend on other `impl` (Dagger-friendly) — enforced; F-011.
- `androidLibrary` / `androidApp` / `androidBinary` use restricted project-dep listsF-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)
Expand Down Expand Up @@ -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 |
Expand Down
33 changes: 18 additions & 15 deletions docs/DEPENDENCY-MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

---

Expand Down Expand Up @@ -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` |
Expand All @@ -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).
Expand Down Expand Up @@ -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 | — | — | — | — | — |
Expand All @@ -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
Expand All @@ -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** |
Expand All @@ -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**.

---

Expand All @@ -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.

Expand All @@ -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).
39 changes: 23 additions & 16 deletions docs/PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
33 changes: 28 additions & 5 deletions plugins/android/src/main/java/androidApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -48,14 +62,23 @@ 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,
androidTestDependencies = androidTestDependencies,
configurationFeatures = kaptConfigurationFeature()
)
}

Loading
Loading