From cae5cad8cb31fabef115105edac2c5a83f29c848 Mon Sep 17 00:00:00 2001 From: Claw Date: Thu, 16 Jul 2026 19:55:50 -0700 Subject: [PATCH] F-063: hard-remove androidLibrary target Drop public DSL, android.library type, registry registration, and restriction rules after F-060/061/062 migration. JVM library keeps the library suffix; AGP androidLibraryFeatureDefinition helper remains for role-typed targets. Update matrix and teaching docs to removed. --- README.md | 6 +- TICKETS.md | 2 +- docs/ANDROID-LIBRARY-DEPRECATION.md | 57 +++++++------- docs/ARCHITECTURE.md | 7 +- docs/COMPOSE.md | 2 +- docs/CONFIGURATION-PERFORMANCE.md | 2 +- docs/DEPENDENCY-MATRIX.md | 24 +++--- docs/GETTING-STARTED.md | 4 +- docs/PROGRESS.md | 19 +++++ docs/PROGRESSIVE-EXAMPLES.md | 2 +- docs/VISION.md | 12 +-- docs/forma-core-api.md | 14 ++-- examples/README.md | 2 +- .../agent-skills/forma-android-targets.md | 5 +- .../agent-skills/forma-dependency-matrix.md | 1 - examples/android/03-res-viewbinding/README.md | 2 +- examples/android/04-shared-libs/README.md | 4 +- plugins/android/README.md | 8 +- .../android/src/main/java/androidLibrary.kt | 77 ------------------- .../forma/android/feature/AndroidLibrary.kt | 5 ++ .../restriction/AndroidRestrictions.kt | 32 ++++---- .../android/target/AndroidTargetRegistry.kt | 26 +++---- .../android/target/AndroidTargetTypes.kt | 5 +- .../forma/config/AndroidProjectSettings.kt | 4 +- .../core/restriction/RestrictionGraphTest.kt | 8 +- 25 files changed, 131 insertions(+), 199 deletions(-) delete mode 100644 plugins/android/src/main/java/androidLibrary.kt diff --git a/README.md b/README.md index 66c8d268..73326814 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ buildscript { ``` Your kotlin android library (role-specific — prefer `androidUtil` / `uiLibrary` / -`impl` over deprecated `androidLibrary`) +`impl`; generic `androidLibrary` was removed in F-063) ``` gradle // Single method, type-safe creation of your target @@ -147,7 +147,6 @@ project-dep type checks + content layout rules from live validators |:----------------------:|:-----------:|:-------:|:----------:| | `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` | ⚠️ deprecated | Generic Android lib escape hatch — **do not use** | see [`docs/ANDROID-LIBRARY-DEPRECATION.md`](docs/ANDROID-LIBRARY-DEPRECATION.md) | | `uiLibrary` | ✅ | Shared UI library for impl/widget | project-dep list | | `widget` | ✅ | Custom View / UI component | project-dep list | | `composeWidget` | ✅ | Compose UI component | always Compose + project-dep list | @@ -157,7 +156,7 @@ project-dep type checks + content layout rules from live validators | `androidUtil` | ✅ | Android library extensions | no `res/` + project-dep list | | `testUtil` | ✅ | Shared code for unit tests | no `res/` + project-dep list | | `util` | ✅ | JVM library extensions | no `res/` + project-dep list | -| `library` | ✅ | JVM library | project-dep list (shares `library` suffix with `androidLibrary`) | +| `library` | ✅ | JVM library | project-dep list (only owner of `library` suffix after F-063) | | `api` | ✅ | Feature external APIs | no `res/` + project-dep list | | `impl` | ✅ | Feature implementation | project-dep list (**no** other `impl`) | | `androidNative` | ✅ | NDK / native | no `res/`; no project-dep validation yet | @@ -174,7 +173,6 @@ That document is generated from each target’s | `api` | `api`, `library` | | `impl` | `api`, `android-util`, `test-util`, `util`, `library`, `ui-library`, `res`, `viewbinding`, `widget`, `compose-widget` | | `library` (JVM) | `util`, `test-util` | -| `androidLibrary` (deprecated) | `library`, `util`, `android-util`, `test-util`, `res`, `api` | | `uiLibrary` | `widget`, `compose-widget`, `util`, `android-util`, `res` | | `util` | `util`, `library` | | `androidUtil` | `android-util`, `test-util`, `res`, `library` | diff --git a/TICKETS.md b/TICKETS.md index 1f15d90e..da04207c 100644 --- a/TICKETS.md +++ b/TICKETS.md @@ -69,7 +69,7 @@ encourages dumping mixed concerns into one bucket. Prefer specific targets. | F-060 | done | Deprecate `androidLibrary` + document flat-structure policy | `@Deprecated` on DSL; VISION + `docs/ANDROID-LIBRARY-DEPRECATION.md`; matrix/README | | F-061 | done | Migrate `application/` sample off `androidLibrary` | di→`androidUtil`, mvvm→`uiLibrary`, navigation→`androidRes`; path renames | | F-062 | done | Reimplement progressive examples / skills without `androidLibrary` | `examples/android/04` + agent skills + README curriculum | -| F-063 | todo | Hard-remove `androidLibrary` target (after consumers migrated) | Drop registry type / docs row once no in-repo callers | +| F-063 | done | Hard-remove `androidLibrary` target (after consumers migrated) | DSL + `android.library` type/registry/restrictions removed; JVM `library` + AGP feature helper kept; matrix/docs updated | ## Backlog (lower priority / historical GitHub) diff --git a/docs/ANDROID-LIBRARY-DEPRECATION.md b/docs/ANDROID-LIBRARY-DEPRECATION.md index 27259832..e55ddf26 100644 --- a/docs/ANDROID-LIBRARY-DEPRECATION.md +++ b/docs/ANDROID-LIBRARY-DEPRECATION.md @@ -1,25 +1,22 @@ -# Deprecating `androidLibrary` (F-060+) +# `androidLibrary` removed (F-063) -## Why +`androidLibrary` (the generic AGP library DSL target with type id `android.library` +and `library` suffix) has been **hard-removed** in F-063. -`androidLibrary` is a **generic AGP library** target. It was a temporary way to -host “shared Android code that isn’t a feature `impl`.” That works against -Forma’s goal: **keep structure flat and role-typed**. +It was a temporary escape hatch that worked against Forma’s core principle: +**keep the dependency graph flat and role-typed**. -Problems: +## Why it existed and why it is gone -1. **Suffix collision** with JVM `library` (`library` name suffix / historical - `LibraryTargetTemplate`) — validators resolve deps by suffix and cannot tell - JVM vs Android library modules apart reliably. -2. **Mixed concerns** — sample historically stuffed DI scopes, MVVM/UI bases, and - navigation XML into the same target kind. -3. **Weak teaching signal** — newcomers reach for `androidLibrary` instead of the - target that matches the module’s job. +- Shared the `library` suffix with JVM `library()` (validator collision). +- Encouraged dumping unrelated concerns into one bucket. +- Weak teaching signal — people reached for the generic target instead of the + role that matched the module. -## Replacement map +## Replacements (use these) -| If the module is… | Use instead | Suffix | -|-------------------|-------------|--------| +| If the module is… | Use | Suffix | +|-------------------|-----|--------| | Pure JVM shared code | `library` | `library` | | Small Android helpers, **no** `res/` | `androidUtil` | `android-util` | | Shared UI bases for `impl` / `widget` | `uiLibrary` | `ui-library` | @@ -30,7 +27,7 @@ Problems: | Feature implementation | `impl` | `impl` | | Feature contracts | `api` | `api` | -## Sample migration (F-061) +## Historical migrations (F-061 / F-062) | Old path | Old DSL | New path | New DSL | |----------|---------|----------|---------| @@ -38,22 +35,20 @@ Problems: | `core/mvvm/library` | `androidLibrary` | `core/mvvm/ui-library` | `uiLibrary` | | `core/navigation/library` | `androidLibrary` | `core/navigation/res` | `androidRes` | -Kotlin **packages** may keep historical `.library` segments to limit churn; -**project path / suffix** is what Forma validates. - -## Matrix tweaks paired with migration - -- `viewBinding` may depend on `ui-library` (shared UI bases without generic library). -- `androidUtil` may depend on JVM `library` (Android helpers wrapping pure JVM code). +Kotlin packages may retain historical `.library` segments; the **project name suffix** +is what the validators enforce. ## Lifecycle -| Ticket | Intent | +| Ticket | Status | |--------|--------| -| **F-060** | `@Deprecated` on DSL + docs/vision | -| **F-061** | `application/` sample migrated | -| **F-062** | Progressive examples + agent skills teach replacements | -| **F-063** | Hard-remove target type / registry entry when nothing in-repo calls it | +| F-060 | Deprecated DSL + docs | +| F-061 | Migrated `application/` sample | +| F-062 | Migrated examples + agent skills | +| F-063 | Hard-removed DSL entry, type registration, restriction rules, and docs | + +**`androidLibrary { }` no longer exists.** Use the role-specific targets above. +The internal `androidLibraryFeatureDefinition` helper (AGP `com.android.library` +wiring) remains for use by `impl`, `uiLibrary`, etc. — it is not a public DSL target. -Until F-063, `androidLibrary { }` still configures modules but should not appear -in new code or tutorials. +See also [`DEPENDENCY-MATRIX.md`](DEPENDENCY-MATRIX.md) (collision note updated). diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index ba7c59f8..855505df 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -131,7 +131,7 @@ Defined in `plugins/android/.../AndroidTargets.kt`: |--------|--------|---------------------| | `BinaryTargetTemplate` | `binary` | `androidBinary` | | `ApplicationTargetTemplate` | `app` | `androidApp` | -| `LibraryTargetTemplate` | `library` | `library` (JVM); deprecated `androidLibrary` shares suffix | +| `LibraryTargetTemplate` | `library` | `library` (JVM only after F-063) | | `UiLibraryTargetTemplate` | `ui-library` | `uiLibrary` | | `NativeTarget` | `native` | `androidNative` | | `UtilTargetTemplate` | `util` | `util` | @@ -158,7 +158,6 @@ when validators change. | `api` | `api`, `library` | no `res/` under `src/main` | | `impl` | `api`, `android-util`, `test-util`, `util`, `library`, `ui-library`, `res`, `viewbinding`, `widget`, `compose-widget` | — | | `library` (JVM) | `util`, `test-util` | — | -| `androidLibrary` (deprecated) | `library`, `util`, `android-util`, `test-util`, `res`, `api` | — | | `uiLibrary` | `widget`, `compose-widget`, `util`, `android-util`, `res` | — | | `util` | `util`, `library` | no `res/` | | `androidUtil` | `android-util`, `test-util`, `res`, `library` | no `res/` | @@ -176,7 +175,7 @@ Notes for later tickets: - `impl` cannot depend on other `impl` (Dagger-friendly) — enforced; F-011. - `androidApp` / `androidBinary` use restricted composition-root lists — F-011 done. -- `androidLibrary` **deprecated** (F-060+); JVM `library` keeps the `library` suffix — see [`ANDROID-LIBRARY-DEPRECATION.md`](ANDROID-LIBRARY-DEPRECATION.md). +- `androidLibrary` **removed** (F-063); only JVM `library` uses the `library` suffix — see [`ANDROID-LIBRARY-DEPRECATION.md`](ANDROID-LIBRARY-DEPRECATION.md). ### 2.3 Feature stack (Android module) @@ -350,7 +349,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~~ (composition-root + library allowlists) | F-011 done | +| ~~`EmptyValidator` on app/binary/(historical androidLibrary)~~ (composition-root + library allowlists) | F-011 done; androidLibrary removed F-063 | | ~~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~~ → per-target flags + `composeWidget` | F-013 done | diff --git a/docs/COMPOSE.md b/docs/COMPOSE.md index faa8f4b3..6d8d147b 100644 --- a/docs/COMPOSE.md +++ b/docs/COMPOSE.md @@ -22,7 +22,7 @@ androidProjectConfiguration( | Setting | Role | |---------|------| -| `compose` | Default value for per-target `compose = …` parameters on `impl`, `androidUtil`, `androidApp`, `uiLibrary`, `androidBinary` (deprecated `androidLibrary` still accepts it). | +| `compose` | Default value for per-target `compose = …` parameters on `impl`, `androidUtil`, `androidApp`, `uiLibrary`, `androidBinary`. | | `composeCompilerVersion` | Written to AGP `composeOptions.kotlinCompilerExtensionVersion` when Compose is enabled. | `composeWidget` modules **always** enable Compose; they ignore the project default diff --git a/docs/CONFIGURATION-PERFORMANCE.md b/docs/CONFIGURATION-PERFORMANCE.md index 73a50886..bcb1adcb 100644 --- a/docs/CONFIGURATION-PERFORMANCE.md +++ b/docs/CONFIGURATION-PERFORMANCE.md @@ -43,7 +43,7 @@ definitions, skip empty repo blocks), not as a claim of a fixed wall-clock %. ## What costs configuration time in Forma -1. **Per-target work** — every `api` / `impl` / `androidLibrary` / … call: +1. **Per-target work** — every `api` / `impl` / `androidUtil` / … call: - suffix validation for self + each project dependency - AGP / Kotlin plugin apply + extension configuration - dependency registration (`applyDependencies`) diff --git a/docs/DEPENDENCY-MATRIX.md b/docs/DEPENDENCY-MATRIX.md index 8d025c23..86b87234 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-16** against `v2` + F-060 androidLibrary deprecation migration. +Last verified: **2026-07-17** against `v2` + F-063 hard-remove of `androidLibrary`. --- @@ -41,7 +41,6 @@ From `plugins/android/.../AndroidTargets.kt`: |----------------|-----------------|-------------| | `androidBinary` | `BinaryTargetTemplate` | `binary` | | `androidApp` | `ApplicationTargetTemplate` | `app` | -| `androidLibrary` (**deprecated**) | `LibraryTargetTemplate` | `library` | | `library` (JVM) | `LibraryTargetTemplate` | `library` | | `uiLibrary` | `UiLibraryTargetTemplate` | `ui-library` | | `androidNative` | `NativeTarget` | `native` | @@ -56,11 +55,12 @@ From `plugins/android/.../AndroidTargets.kt`: | `widget` | `WidgetTargetTemplate` | `widget` | | `composeWidget` | `ComposeWidgetTargetTemplate` | `compose-widget` | -**Collision note:** JVM `library` and Android `androidLibrary` share the same -suffix `library` / `LibraryTargetTemplate`. The DSL functions differ (Kotlin -JVM features vs AGP library features), but project-name validation cannot -tell them apart. **Design (F-020):** unique `TargetType.id` with shared -suffix allowed for Gradle names — see [`forma-core-api.md`](forma-core-api.md) §7. +**Collision note:** Only JVM `library` uses the `library` suffix (F-063). +Historical `androidLibrary` (also using `library` suffix via `LibraryTargetTemplate`) +was removed after F-060–F-062 migration to role-specific targets (`androidUtil`, +`uiLibrary`, `androidRes`, `viewBinding`, `impl`). Validators still match by +suffix, so `*-library` JVM modules are accepted where `library` is allowed. +See [`forma-core-api.md`](forma-core-api.md) §7 for the engine design. README historically said `androidWidget` / `androidUtils` / `testUtils` / `utils` / `androidTestUtils` — the **code** entrypoints are `widget`, @@ -78,7 +78,6 @@ 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, compose-widget)` | `api`, `android-util`, `test-util`, `util`, `library`, `ui-library`, `res`, `viewbinding`, `widget`, `compose-widget` | | `library` (JVM) | `library.kt` | `validator(util, test-util)` | `util`, `test-util` | -| `androidLibrary` (**deprecated**) | `androidLibrary.kt` | `validator(library, util, android-util, test-util, res, api)` | `library`, `util`, `android-util`, `test-util`, `res`, `api` | | `uiLibrary` | `uiLibrary.kt` | `validator(widget, compose-widget, util, android-util, res)` | `widget`, `compose-widget`, `util`, `android-util`, `res` | | `util` | `util.kt` | `validator(util, library)` | `util`, `library` | | `androidUtil` | `androidUtil.kt` | `validator(android-util, test-util, res, library)` | `android-util`, `test-util`, `res`, `library` | @@ -103,9 +102,6 @@ These follow from the table (not from separate deny-lists): - **`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). -- **`androidLibrary` is deprecated (F-060)** — temporary generic escape hatch; prefer `androidUtil` / `uiLibrary` / `androidRes` / `viewBinding` / `impl` / JVM `library`. See [`ANDROID-LIBRARY-DEPRECATION.md`](ANDROID-LIBRARY-DEPRECATION.md). - **`viewBinding` may depend on `ui-library`** — shared UI bases without generic library (F-061). - **`androidUtil` may depend on JVM `library`** — Android helpers wrapping pure JVM code (F-061). - **`androidApp` / `androidBinary` cannot depend on other `binary`** — @@ -117,7 +113,7 @@ These follow from the table (not from separate deny-lists): ### Compose flags (not project-dep rules) -Separate from suffix validation: `impl`, `androidLibrary`, `androidUtil`, +Separate from suffix validation: `impl`, `androidUtil`, `androidApp`, `uiLibrary`, and `androidBinary` accept `compose: Boolean` (default = project `androidProjectConfiguration(compose=…)`). `composeWidget` **always** enables Compose. See [`COMPOSE.md`](COMPOSE.md). @@ -160,7 +156,6 @@ Rows = **consumer**. Columns = **dependency type (suffix)**. | **api** | Y | — | Y | — | — | — | — | — | — | — | — | — | — | — | — | | **impl** | Y | — | Y | Y | Y | Y | Y | — | Y | Y | Y | Y | — | — | — | | **library** (JVM) | — | — | — | — | Y | Y | — | — | — | — | — | — | — | — | — | -| **androidLibrary** | Y | — | Y | — | Y | Y | Y | — | Y | — | — | — | — | — | — | | **uiLibrary** | — | — | — | — | Y | — | Y | — | Y | — | Y | Y | — | — | — | | **util** | — | — | Y | — | Y | — | — | — | — | — | — | — | — | — | — | | **androidUtil** | — | — | Y | — | — | Y | Y | — | Y | — | — | — | — | — | — | @@ -184,13 +179,12 @@ allowed list (e.g. `api`→`api` **Y**, `impl`→`impl` **—**, `widget`→`wid The historical README table used columns as *consumers* and rows as *dependencies*, mixed aspirational edges, and omitted several types -(`uiLibrary`, `viewBinding`, `library` JVM vs `androidLibrary`, `native`). +(`uiLibrary`, `viewBinding`, `library` JVM, `native`). Notable mismatches fixed by treating **this document** as truth: | Topic | Old README implication | Live code | |-------|------------------------|-----------| -| `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** | diff --git a/docs/GETTING-STARTED.md b/docs/GETTING-STARTED.md index cf0c4d92..4c31222f 100644 --- a/docs/GETTING-STARTED.md +++ b/docs/GETTING-STARTED.md @@ -292,7 +292,7 @@ dependency**, and the allowed set — fix the edge, don’t weaken the graph. | `viewBinding` | `viewbinding` | Layout XML (+ light binding-facing types) | | `widget` | `widget` | Custom Views | | `composeWidget` | `compose-widget` | Compose UI components (always Compose) | -| ~~`androidLibrary`~~ | `library` | **Deprecated** — use role-specific targets ([deprecation guide](ANDROID-LIBRARY-DEPRECATION.md)) | +| ~~`androidLibrary`~~ | — | **Removed (F-063)** — use role-specific targets ([guide](ANDROID-LIBRARY-DEPRECATION.md)) | | `library` | `library` | Shared pure JVM library | | `uiLibrary` | `ui-library` | Shared UI building blocks for widgets | | `util` / `androidUtil` / `testUtil` | `util` / `android-util` / `test-util` | Small helpers | @@ -339,7 +339,7 @@ validator intent (F-011). 1. **`impl` → `impl` is forbidden.** Cross-feature collaboration goes through `api` (or shared `core` libraries). -2. **Do not use deprecated `androidLibrary`.** Prefer `androidUtil` / `uiLibrary` / +2. **`androidLibrary` is gone (F-063).** Prefer `androidUtil` / `uiLibrary` / `androidRes` / `viewBinding` so the graph stays flat and role-typed ([ANDROID-LIBRARY-DEPRECATION.md](ANDROID-LIBRARY-DEPRECATION.md)). 3. **`api` cannot contain `res/`.** Put resources in `androidRes` / `viewBinding`. diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 49790a6d..2d6182eb 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -2,6 +2,25 @@ Newest entries first. +## 2026-07-17 — F-063: hard-remove `androidLibrary` + +- **Ticket:** F-063 → `done` (P6 flat-structure complete) +- **Branch:** `forma/F-063-hard-remove-androidLibrary` from `origin/v2` @ `773d061` +- **Skills/modes:** Grok Build `--mode full` (design + implement hit max-turns with tree on disk); Hermes finish path: remaining docs, TICKETS/PROGRESS, verify, PR +- **Code:** + - Deleted `plugins/android/src/main/java/androidLibrary.kt` (public DSL) + - Removed `AndroidTargetTypes.library` (`android.library`) + - Dropped registry consumer registration + restriction-graph consumer rules + - Rewrote allow-lists (`api`/`impl`/`util`/`androidUtil`/`viewBinding`/`app`/`binary`) to depend on `jvmLibrary` (same `library` suffix) + - Kept `androidLibraryFeatureDefinition` (AGP wiring for impl/uiLibrary/etc.) + JVM `library()` + - Core unit tests still use synthetic `android.library` types for suffix-collision engine docs +- **Docs:** DEPENDENCY-MATRIX (first), ANDROID-LIBRARY-DEPRECATION lifecycle, README, ARCHITECTURE, VISION, GETTING-STARTED, COMPOSE, CONFIGURATION-PERFORMANCE, progressive examples + agent skills, plugins/android README +- **Verify (real host, OpenJDK via `scripts/env-mac.sh`):** + - `plugins/ ./gradlew build` → **BUILD SUCCESSFUL** (78 tasks) + - `application/ ./gradlew build` → **BUILD SUCCESSFUL** (2157 tasks) +- **Blockers:** none +- **Next:** prioritized queue empty again unless user adds F-xxx or promotes backlog (e.g. #110, #97, #88, #82, Portal #133) + ## 2026-07-16 — F-060/061/062: deprecate androidLibrary, flatten sample + examples - **Tickets:** F-060, F-061, F-062 → `done`; F-063 hard-remove remains `todo` diff --git a/docs/PROGRESSIVE-EXAMPLES.md b/docs/PROGRESSIVE-EXAMPLES.md index d3365541..4571afa2 100644 --- a/docs/PROGRESSIVE-EXAMPLES.md +++ b/docs/PROGRESSIVE-EXAMPLES.md @@ -23,7 +23,7 @@ narrative tutorials when you want a **minimal buildable project per concept**. | `api` / `impl` | 02 | 02 | platform skills + matrix | | `viewBinding` | 03 | — | forma-android-targets | | `library` / `util` | 04 | 03 | platform skills | -| `androidUtil` (not deprecated `androidLibrary`) | 04 | — | forma-android-targets | +| `androidUtil` (not removed `androidLibrary`) | 04 | — | forma-android-targets | | `widget` / `uiLibrary` | 05 | — | forma-android-targets | | Compose + `composeWidget` | 06 | — | forma-compose | | Multi-feature composition | 07 | 04 | forma-project-layout | diff --git a/docs/VISION.md b/docs/VISION.md index 213c9078..b807e37a 100644 --- a/docs/VISION.md +++ b/docs/VISION.md @@ -13,11 +13,11 @@ Forma exists to **protect a flat, role-typed module graph**. Each target type is - **Prefer the most specific target** that matches the module’s job. - **Composition of features** happens only at `androidApp` / `androidBinary` (and JVM `binary`) — never by stacking feature `impl`s on each other. -- **Generic escape hatches fight the product.** `androidLibrary` is **deprecated** - (F-060+): it collides with JVM `library` on the `library` suffix and invites - mixed DI/UI/res dumps that the matrix cannot reason about. Migrate to - role-specific targets (see [`GETTING-STARTED.md`](GETTING-STARTED.md) cheat - sheet and F-060 notes in `PROGRESS.md`). +- **Generic escape hatches fight the product.** `androidLibrary` was **removed** + (F-063): it collided with JVM `library` on the `library` suffix and invited + mixed DI/UI/res dumps that the matrix cannot reason about. Use role-specific + targets only (see [`GETTING-STARTED.md`](GETTING-STARTED.md) and + [`ANDROID-LIBRARY-DEPRECATION.md`](ANDROID-LIBRARY-DEPRECATION.md)). ## Architectural split @@ -39,7 +39,7 @@ Concrete stacks built **on** forma-core: 1. **Android** — role-typed target set (`api`, `impl`, `androidUtil`, `uiLibrary`, `androidRes`, `viewBinding`, `androidBinary`, …) with a strict dependency matrix; Dagger2-friendly `api`/`impl` conventions; external deps catalog - patterns. (`androidLibrary` deprecated — do not teach it as the default.) + patterns. (`androidLibrary` removed in F-063 — do not teach or reintroduce it.) 2. **JVM** — pure JVM targets and samples reusing the same restriction model. 3. **Bazel** — later adapter that reuses forma-core concepts (types + restrictions) rather than forking the rules engine. diff --git a/docs/forma-core-api.md b/docs/forma-core-api.md index 693b8fa9..ff3b02c3 100644 --- a/docs/forma-core-api.md +++ b/docs/forma-core-api.md @@ -444,14 +444,18 @@ Do not skip to JVM targets (F-030) until F-023 is done. ## 7. Design decision: `library` suffix collision -**Problem:** JVM `library { }` and Android `androidLibrary { }` both use -`LibraryTargetTemplate` / suffix `library`. Name validation and dependency -allow-lists **cannot distinguish** them today +**Historical problem (pre-F-063):** JVM `library { }` and Android `androidLibrary { }` +both used `LibraryTargetTemplate` / suffix `library`. Name validation and dependency +allow-lists could not distinguish them ([`DEPENDENCY-MATRIX.md`](DEPENDENCY-MATRIX.md) collision note). +**Product resolution (F-063):** `androidLibrary` was hard-removed. Only JVM +`library` (`jvm.library`) remains as a live consumer of the `library` suffix. +The engine design below still applies for any future shared-suffix cases. + **Decision for forma-core:** -1. Every `TargetType` has a **unique `id`** (`jvm.library` vs `android.library`) +1. Every `TargetType` has a **unique `id`** (`jvm.library` vs historical `android.library`) even when `nameSuffix` is shared. 2. Restriction rules key off **`TargetType` identity / id**, not suffix alone. 3. **Default name matching remains suffix-based** for Gradle project names so @@ -465,7 +469,7 @@ allow-lists **cannot distinguish** them today ambiguity. 5. Optional later hardening (not F-020): rename Android library suffix to `android-library` or require path conventions — product change, needs its - own ticket after core lands. + own ticket after core lands. (Superseded for androidLibrary by F-063 removal.) This unblocks registry design without forcing a breaking sample rename in F-021. diff --git a/examples/README.md b/examples/README.md index 1833c368..61aa4733 100644 --- a/examples/README.md +++ b/examples/README.md @@ -30,7 +30,7 @@ Gold-standard product apps remain [`application/`](../application/) (Android) an | 01 | `android/01-hello-apk` | `androidProjectConfiguration`, `androidBinary`, `androidApp`, `androidRes` | | 02 | `android/02-feature-api-impl` | `api`, `impl` | | 03 | `android/03-res-viewbinding` | feature `androidRes`, `viewBinding` | -| 04 | `android/04-shared-libs` | `library`, `util`, `androidUtil` (no deprecated `androidLibrary`) | +| 04 | `android/04-shared-libs` | `library`, `util`, `androidUtil` (no removed `androidLibrary`) | | 05 | `android/05-widget-ui` | `widget`, `uiLibrary` | | 06 | `android/06-compose` | `compose` flags, `composeWidget` | | 07 | `android/07-multi-feature` | two features at composition root | diff --git a/examples/agent-skills/forma-android-targets.md b/examples/agent-skills/forma-android-targets.md index a7bf6bcb..6db213c2 100644 --- a/examples/agent-skills/forma-android-targets.md +++ b/examples/agent-skills/forma-android-targets.md @@ -18,7 +18,6 @@ Plugin: `tools.forma.android`. Register happens on first DSL use via `AndroidTar | `library` | `library` | pure JVM library | 04 | | `util` | `util` | no res/ | 04 | | `androidUtil` | `android-util` | no res/ | 04 | -| ~~`androidLibrary`~~ | `library` | **Deprecated** — do not use | — | | `widget` | `widget` | Custom View | 05 | | `uiLibrary` | `ui-library` | shared UI blocks | 05 | | `composeWidget` | `compose-widget` | always Compose | 06 | @@ -37,7 +36,7 @@ impl(packageName = "…", dependencies = deps(target(":feature:x:api"))) viewBinding(packageName = "…", dependencies = deps(target(":feature:x:res"))) widget(packageName = "…") composeWidget(packageName = "…", dependencies = deps(/* compose GAVs */)) -// androidLibrary(…) // DEPRECATED — use androidUtil / uiLibrary / androidRes / … +// androidLibrary(…) // REMOVED F-063 — use androidUtil / uiLibrary / androidRes / … androidUtil(packageName = "…") util(packageName = "…") library(packageName = "…") @@ -50,6 +49,6 @@ androidTestUtil(packageName = "…") - `impl` → `impl` - `api` shipping `res/` -- deprecated `androidLibrary` (use role-specific targets) +- removed `androidLibrary` (use role-specific targets; F-063) - Wrong suffix for DSL - Relying on transitive feature wiring instead of listing api+impl on roots diff --git a/examples/agent-skills/forma-dependency-matrix.md b/examples/agent-skills/forma-dependency-matrix.md index de7474a1..babe640b 100644 --- a/examples/agent-skills/forma-dependency-matrix.md +++ b/examples/agent-skills/forma-dependency-matrix.md @@ -14,7 +14,6 @@ description: Project-dep allowlists and how to fix validator failures. | `api` | `api`, `library` | | `impl` | api, utils, library, ui-library, res, viewbinding, widget, compose-widget — **not** other `impl` | | `androidApp` / `androidBinary` | api, impl, shared UI/libs (composition roots) | -| ~~`androidLibrary`~~ | **deprecated** — prefer androidUtil/uiLibrary/androidRes | | `androidUtil` | android-util, test-util, res, **library** (JVM) | | `uiLibrary` | widget, compose-widget, util, android-util, res | diff --git a/examples/android/03-res-viewbinding/README.md b/examples/android/03-res-viewbinding/README.md index 702be3fa..abc29b75 100644 --- a/examples/android/03-res-viewbinding/README.md +++ b/examples/android/03-res-viewbinding/README.md @@ -15,4 +15,4 @@ printf 'sdk.dir=%s\n' "$ANDROID_HOME" > local.properties ``` ## Next -04 adds shared `library` / `util` / `androidUtil` (no deprecated `androidLibrary`). +04 adds shared `library` / `util` / `androidUtil` (no removed `androidLibrary`). diff --git a/examples/android/04-shared-libs/README.md b/examples/android/04-shared-libs/README.md index 7e3890cb..cdfa4d10 100644 --- a/examples/android/04-shared-libs/README.md +++ b/examples/android/04-shared-libs/README.md @@ -1,12 +1,12 @@ # 04 — shared-libs (Android) -**Goal:** Shared pure-JVM and Android libraries outside features — **role-typed**, no generic `androidLibrary`. +**Goal:** Shared pure-JVM and Android libraries outside features — **role-typed**, no generic `androidLibrary` (removed F-063). ## Features introduced - `library` (JVM) - `util` (JVM helpers) - `androidUtil` (Android helpers, no res/) -- (intentionally **no** `androidLibrary` — deprecated; see `docs/ANDROID-LIBRARY-DEPRECATION.md`) +- (intentionally **no** `androidLibrary` — removed; see `docs/ANDROID-LIBRARY-DEPRECATION.md`) ## Layout - `common/library` — pure JVM diff --git a/plugins/android/README.md b/plugins/android/README.md index 243ff8d5..4a2ae1f3 100644 --- a/plugins/android/README.md +++ b/plugins/android/README.md @@ -10,11 +10,11 @@ The androidApp target is used to configure Android applications. It contains cod An androidApp cannot depend on androidBinary. The app target should only provide high-level application configurations, components, and resources. Depending on androidBinary could tightly couple the app code to distribution details like signing, ProGuard, versioning etc. Isolating androidApp allows changing distribution methods without impacting Application code. -### androidLibrary (deprecated) -**Do not use for new modules.** Generic AGP-library escape hatch that undermines -Forma's flat, role-typed graph. Prefer `androidUtil`, `uiLibrary`, `androidRes`, +### androidLibrary (removed F-063) +**Gone.** The generic AGP-library escape hatch was hard-removed so Forma can keep a +flat, role-typed graph. Use `androidUtil`, `uiLibrary`, `androidRes`, `viewBinding`, `widget`, or `impl`. See `docs/ANDROID-LIBRARY-DEPRECATION.md`. -Still present until hard-removal (F-063). +The internal `androidLibraryFeatureDefinition` helper (AGP plugin wiring) remains. ### androidWidget The androidWidget target provides reusable UI components that can be shared between apps. These contain layout XML, drawables, custom views, composables, etc. that abstract UI elements away from app code. diff --git a/plugins/android/src/main/java/androidLibrary.kt b/plugins/android/src/main/java/androidLibrary.kt deleted file mode 100644 index 3275dee9..00000000 --- a/plugins/android/src/main/java/androidLibrary.kt +++ /dev/null @@ -1,77 +0,0 @@ -import org.gradle.api.Project -import tools.forma.android.feature.AndroidLibraryFeatureConfiguration -import tools.forma.android.feature.androidLibraryFeatureDefinition -import tools.forma.android.feature.applyFeatures -import tools.forma.android.feature.kaptConfigurationFeature -import tools.forma.android.feature.kotlinAndroidFeatureDefinition -import tools.forma.android.target.AndroidTargetRegistry -import tools.forma.android.target.AndroidTargetTypes -import tools.forma.owners.NoOwner -import tools.forma.owners.Owner -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.asValidator -import tools.forma.validation.validate - -/** - * **Deprecated.** Generic Android library target — a temporary escape hatch that - * flattens Forma's typed structure back into "just an Android library". - * - * Prefer a **role-specific** target so the dependency matrix can protect a flat - * graph: - * - shared Android helpers (no `res/`) → [androidUtil] - * - shared UI bases for impl/widget → [uiLibrary] - * - resources only → [androidRes] - * - layouts only → [viewBinding] - * - feature UI/DI → [impl] - * - pure JVM → [library] - * - * Remains functional until hard-removal (F-063) so existing consumers can migrate. - */ -@Deprecated( - message = "androidLibrary is a temporary generic escape hatch. Use androidUtil, " + - "uiLibrary, androidRes, viewBinding, impl, or library so Forma can keep structure flat.", - replaceWith = ReplaceWith("androidUtil(packageName, owner, visibility, dependencies, testDependencies, compose)") -) -fun Project.androidLibrary( - packageName: String, - owner: Owner = NoOwner, - visibility: Visibility = Public, - dependencies: FormaDependency = emptyDependency(), - testDependencies: NamedDependency = emptyDependency(), - androidTestDependencies: NamedDependency = emptyDependency(), - testInstrumentationRunner: String = androidJunitRunner, - buildConfiguration: BuildConfiguration = BuildConfiguration(), - consumerMinificationFiles: Set = emptySet(), - manifestPlaceholders: Map = emptyMap(), - /** Enable Jetpack Compose; defaults to project-wide `compose` setting. */ - compose: Boolean = Forma.settings.compose, -): TargetBuilder { - AndroidTargetRegistry.selfValidator(AndroidTargetTypes.library).asValidator().validate(target) - val libraryFeatureConfiguration = AndroidLibraryFeatureConfiguration( - packageName, - buildConfiguration, - testInstrumentationRunner, - consumerMinificationFiles, - manifestPlaceholders, - compose = compose, - ) - applyFeatures( - androidLibraryFeatureDefinition(libraryFeatureConfiguration), - kotlinAndroidFeatureDefinition() - ) - - applyDependencies( - validator = AndroidTargetRegistry.validatorFor(AndroidTargetTypes.library).asValidator(), - dependencies = dependencies, - testDependencies = testDependencies, - androidTestDependencies = androidTestDependencies, - configurationFeatures = kaptConfigurationFeature() - ) - - return TargetBuilder(this) -} diff --git a/plugins/android/src/main/java/tools/forma/android/feature/AndroidLibrary.kt b/plugins/android/src/main/java/tools/forma/android/feature/AndroidLibrary.kt index c96f47fc..c1ee4684 100644 --- a/plugins/android/src/main/java/tools/forma/android/feature/AndroidLibrary.kt +++ b/plugins/android/src/main/java/tools/forma/android/feature/AndroidLibrary.kt @@ -21,6 +21,11 @@ class AndroidLibraryFeatureConfiguration( val selfValidator: Validator = validator(LibraryTargetTemplate) ) +/** + * AGP feature wiring for the `com.android.library` plugin. + * Applied by role-specific targets (impl, uiLibrary, androidUtil, viewBinding, widget, ...). + * This is **not** the removed `androidLibrary` DSL target (F-063). + */ fun androidLibraryFeatureDefinition( featureConfiguration: AndroidLibraryFeatureConfiguration ) = FeatureDefinition( diff --git a/plugins/android/src/main/java/tools/forma/android/restriction/AndroidRestrictions.kt b/plugins/android/src/main/java/tools/forma/android/restriction/AndroidRestrictions.kt index 7c4214c2..b43cc4eb 100644 --- a/plugins/android/src/main/java/tools/forma/android/restriction/AndroidRestrictions.kt +++ b/plugins/android/src/main/java/tools/forma/android/restriction/AndroidRestrictions.kt @@ -13,14 +13,18 @@ import tools.forma.core.target.TargetType * * Rules are keyed by TargetType (id) not suffix, satisfying §3.3 / §7. * Critical: `impl` does not allow `impl`. + * + * Note: androidLibrary (android.library type) hard-removed F-063; only JVM library() remains for suffix "library". */ object AndroidRestrictionKit { - /** All Android TargetTypes in registration order (convenience). */ + /** All Android TargetTypes in registration order (convenience). + * Note: `android.library` (historical androidLibrary target) removed in F-063. + * Only `jvm.library` now owns the `library` suffix. + */ val all: List = listOf( AndroidTargetTypes.api, AndroidTargetTypes.impl, - AndroidTargetTypes.library, AndroidTargetTypes.jvmLibrary, AndroidTargetTypes.uiLibrary, AndroidTargetTypes.native, @@ -43,31 +47,27 @@ object AndroidRestrictionKit { fun register(graph: MutableRestrictionGraph) { val t = AndroidTargetTypes - // api: only api + library (JVM contract layer) - graph.allow(t.api, t.api, t.library) + // api: only api + jvm library (JVM contract layer) + graph.allow(t.api, t.api, t.jvmLibrary) // impl: api + shared + ui building blocks; NO impl (Dagger boundaries) graph.allow( t.impl, - t.api, t.androidUtil, t.testUtil, t.util, t.library, + t.api, t.androidUtil, t.testUtil, t.util, t.jvmLibrary, t.uiLibrary, t.res, t.viewBinding, t.widget, t.composeWidget ) // JVM `library` (pure Kotlin/JVM target): only util + test-util (no api/impl/res per matrix) graph.allow(t.jvmLibrary, t.util, t.testUtil) - // androidLibrary: library + util + android-util + test-util + res + api (no impl, no widgets) - // Distinct consumer id (android.library) from jvm.library prevents merge in graph. - graph.allow(t.library, t.library, t.util, t.androidUtil, t.testUtil, t.res, t.api) - // uiLibrary graph.allow(t.uiLibrary, t.widget, t.composeWidget, t.util, t.androidUtil, t.res) - // util (JVM): util + library - graph.allow(t.util, t.util, t.library) + // util (JVM): util + jvm library + graph.allow(t.util, t.util, t.jvmLibrary) // androidUtil — may depend on pure JVM library (helpers wrapping shared code) - graph.allow(t.androidUtil, t.androidUtil, t.testUtil, t.res, t.library) + graph.allow(t.androidUtil, t.androidUtil, t.testUtil, t.res, t.jvmLibrary) // testUtil graph.allow(t.testUtil, t.testUtil, t.util) @@ -84,23 +84,23 @@ object AndroidRestrictionKit { // composeWidget (symmetric with widget for coexistence) graph.allow(t.composeWidget, t.uiLibrary, t.composeWidget, t.widget, t.util, t.androidUtil, t.res) - // viewBinding — ui-library allowed so shared UI bases are not stuffed into androidLibrary + // viewBinding — ui-library allowed for shared UI bases (post androidLibrary removal) graph.allow( t.viewBinding, - t.api, t.widget, t.composeWidget, t.res, t.library, t.androidUtil, t.uiLibrary + t.api, t.widget, t.composeWidget, t.res, t.jvmLibrary, t.androidUtil, t.uiLibrary ) // androidApp (composition root) graph.allow( t.app, - t.api, t.impl, t.library, t.util, t.androidUtil, t.testUtil, t.res, + t.api, t.impl, t.jvmLibrary, t.util, t.androidUtil, t.testUtil, t.res, t.viewBinding, t.widget, t.composeWidget, t.uiLibrary ) // androidBinary (composition root) graph.allow( t.binary, - t.app, t.api, t.impl, t.library, t.util, t.androidUtil, t.testUtil, t.res, + t.app, t.api, t.impl, t.jvmLibrary, t.util, t.androidUtil, t.testUtil, t.res, t.viewBinding, t.widget, t.composeWidget, t.uiLibrary ) diff --git a/plugins/android/src/main/java/tools/forma/android/target/AndroidTargetRegistry.kt b/plugins/android/src/main/java/tools/forma/android/target/AndroidTargetRegistry.kt index ad5ef0f0..d47b47f2 100644 --- a/plugins/android/src/main/java/tools/forma/android/target/AndroidTargetRegistry.kt +++ b/plugins/android/src/main/java/tools/forma/android/target/AndroidTargetRegistry.kt @@ -12,6 +12,8 @@ import tools.forma.core.validation.OnlyResourcesUnderMain * Initialized explicitly via [registerAndroidDefaults] from [androidProjectConfiguration]. * * DSL entrypoints obtain self + dependency validators from here (no more hand-written allow-lists). + * Note: the historical `androidLibrary` target (android.library) was hard-removed in F-063. + * Only JVM `library` (jvm.library) now uses the `library` suffix. */ object AndroidTargetRegistry : TargetRegistry by DefaultTargetRegistry() @@ -33,7 +35,7 @@ fun registerAndroidDefaults(registry: TargetRegistry = AndroidTargetRegistry) { registry.register( TargetRegistration( type = t.api, - allowedDependencies = setOf(t.api, t.library), + allowedDependencies = setOf(t.api, t.jvmLibrary), contentRules = noRes ) ) @@ -43,7 +45,7 @@ fun registerAndroidDefaults(registry: TargetRegistry = AndroidTargetRegistry) { TargetRegistration( type = t.impl, allowedDependencies = setOf( - t.api, t.androidUtil, t.testUtil, t.util, t.library, + t.api, t.androidUtil, t.testUtil, t.util, t.jvmLibrary, t.uiLibrary, t.res, t.viewBinding, t.widget, t.composeWidget ) ) @@ -57,14 +59,6 @@ fun registerAndroidDefaults(registry: TargetRegistry = AndroidTargetRegistry) { ) ) - // androidLibrary consumer (distinct id from jvmLibrary) - registry.register( - TargetRegistration( - type = t.library, - allowedDependencies = setOf(t.library, t.util, t.androidUtil, t.testUtil, t.res, t.api) - ) - ) - // uiLibrary registry.register( TargetRegistration( @@ -77,7 +71,7 @@ fun registerAndroidDefaults(registry: TargetRegistry = AndroidTargetRegistry) { registry.register( TargetRegistration( type = t.util, - allowedDependencies = setOf(t.util, t.library), + allowedDependencies = setOf(t.util, t.jvmLibrary), contentRules = noRes ) ) @@ -86,7 +80,7 @@ fun registerAndroidDefaults(registry: TargetRegistry = AndroidTargetRegistry) { registry.register( TargetRegistration( type = t.androidUtil, - allowedDependencies = setOf(t.androidUtil, t.testUtil, t.res, t.library), + allowedDependencies = setOf(t.androidUtil, t.testUtil, t.res, t.jvmLibrary), contentRules = noRes ) ) @@ -133,12 +127,12 @@ fun registerAndroidDefaults(registry: TargetRegistry = AndroidTargetRegistry) { ) ) - // viewBinding — may use shared UI bases (ui-library) after androidLibrary deprecation + // viewBinding — may use shared UI bases (ui-library) registry.register( TargetRegistration( type = t.viewBinding, allowedDependencies = setOf( - t.api, t.widget, t.composeWidget, t.res, t.library, t.androidUtil, t.uiLibrary + t.api, t.widget, t.composeWidget, t.res, t.jvmLibrary, t.androidUtil, t.uiLibrary ), contentRules = onlyLayouts ) @@ -149,7 +143,7 @@ fun registerAndroidDefaults(registry: TargetRegistry = AndroidTargetRegistry) { TargetRegistration( type = t.app, allowedDependencies = setOf( - t.api, t.impl, t.library, t.util, t.androidUtil, t.testUtil, t.res, + t.api, t.impl, t.jvmLibrary, t.util, t.androidUtil, t.testUtil, t.res, t.viewBinding, t.widget, t.composeWidget, t.uiLibrary ), contentRules = noRes @@ -161,7 +155,7 @@ fun registerAndroidDefaults(registry: TargetRegistry = AndroidTargetRegistry) { TargetRegistration( type = t.binary, allowedDependencies = setOf( - t.app, t.api, t.impl, t.library, t.util, t.androidUtil, t.testUtil, t.res, + t.app, t.api, t.impl, t.jvmLibrary, t.util, t.androidUtil, t.testUtil, t.res, t.viewBinding, t.widget, t.composeWidget, t.uiLibrary ), contentRules = noRes diff --git a/plugins/android/src/main/java/tools/forma/android/target/AndroidTargetTypes.kt b/plugins/android/src/main/java/tools/forma/android/target/AndroidTargetTypes.kt index 44c4959c..26f330c3 100644 --- a/plugins/android/src/main/java/tools/forma/android/target/AndroidTargetTypes.kt +++ b/plugins/android/src/main/java/tools/forma/android/target/AndroidTargetTypes.kt @@ -5,7 +5,7 @@ import tools.forma.core.target.targetType /** * Stable TargetType instances for Android platform (F-021). - * Ids are unique even when nameSuffix collides (e.g. "library" used by JVM + androidLibrary). + * Ids are unique even when nameSuffix collides (e.g. "library" used by JVM `library()` target). * These live in :android (platform owns concrete types); core holds pure engine. * * These parallel the legacy *TargetTemplate objects for now (F-021); full registry migration F-023. @@ -13,8 +13,7 @@ import tools.forma.core.target.targetType object AndroidTargetTypes { val api: TargetType = targetType("android.api", "api") val impl: TargetType = targetType("android.impl", "impl") - val library: TargetType = targetType("android.library", "library") // androidLibrary consumer (distinct from jvm.library) - val jvmLibrary: TargetType = targetType("jvm.library", "library") // JVM library() consumer + val jvmLibrary: TargetType = targetType("jvm.library", "library") // JVM library() consumer (suffix shared with historical androidLibrary) val uiLibrary: TargetType = targetType("android.ui-library", "ui-library") val native: TargetType = targetType("android.native", "native") val util: TargetType = targetType("jvm.util", "util") // JVM util target (distinct id from android.android-util) diff --git a/plugins/config/src/main/java/tools/forma/config/AndroidProjectSettings.kt b/plugins/config/src/main/java/tools/forma/config/AndroidProjectSettings.kt index 1db1bf5d..0fc1af06 100644 --- a/plugins/config/src/main/java/tools/forma/config/AndroidProjectSettings.kt +++ b/plugins/config/src/main/java/tools/forma/config/AndroidProjectSettings.kt @@ -30,8 +30,8 @@ data class AndroidProjectSettings( val repositories: RepositoryHandler.() -> Unit, /** * Project-wide default for per-target `compose` flags - * (`impl`, `androidLibrary`, `androidUtil`, `androidApp`, `uiLibrary`, - * `androidBinary`). Individual targets may still pass `compose = true/false` + * (`impl`, `androidUtil`, `androidApp`, `uiLibrary`, `androidBinary`). + * Individual targets may still pass `compose = true/false` * to override. Does **not** auto-enable `composeWidget` modules (those always * enable Compose themselves). */ diff --git a/plugins/core/src/test/java/tools/forma/core/restriction/RestrictionGraphTest.kt b/plugins/core/src/test/java/tools/forma/core/restriction/RestrictionGraphTest.kt index 65c7bca3..737db52f 100644 --- a/plugins/core/src/test/java/tools/forma/core/restriction/RestrictionGraphTest.kt +++ b/plugins/core/src/test/java/tools/forma/core/restriction/RestrictionGraphTest.kt @@ -15,6 +15,8 @@ class RestrictionGraphTest { private val res = targetType("android.res", "res") // Simulate shared suffix collision per forma-core-api §7 (different ids, same suffix) + // Note: these are synthetic TargetTypes for core engine testing only. + // The live `android.library` type was removed in F-063; only `jvm.library` remains for "library" suffix in product. private val jvmLibrary = targetType("jvm.library", "library") private val androidLibrary = targetType("android.library", "library") @@ -72,7 +74,7 @@ class RestrictionGraphTest { val candidates = listOf(jvmLibrary, androidLibrary).filter { it.nameSuffix == "library" } val allowedByName = candidates.any { g.isAllowed(impl, it) } - // Since androidLibrary is allowed, name "core-library" should be accepted under collision rule + // Since (synthetic) androidLibrary type is allowed in this test graph, name "core-library" should be accepted under collision rule assertTrue(allowedByName) // If neither is allowed, deny @@ -106,6 +108,7 @@ class RestrictionGraphTest { // Documents F-021 fix: separate ids (jvm.library vs android.library) for same suffix // ensures graph.allow() for one does not merge into the other (see DEPENDENCY-MATRIX // and forma-core-api.md §7). Uses synthetic types (core test stays independent of android kit). + // The real android.library consumer registration was removed in F-063. val jvmLib = targetType("jvm.library", "library") val androidLib = targetType("android.library", "library") val jvmUtil = targetType("jvm.util", "util") @@ -118,7 +121,8 @@ class RestrictionGraphTest { // JVM library matrix (per library.kt + DEPENDENCY-MATRIX) g.allow(jvmLib, jvmUtil, testUtilT) - // androidLibrary matrix (per androidLibrary.kt + DEPENDENCY-MATRIX) + // Historical androidLibrary matrix (per removed androidLibrary.kt + DEPENDENCY-MATRIX at time of F-063) + // Kept here as synthetic to exercise forma-core suffix-collision engine (distinct ids, same suffix). g.allow(androidLib, androidLib, jvmUtil, androidUtil, testUtilT, resT, api) // Verify distinct rules (no accidental merge from duplicate consumer id)