Skip to content

Commit 687f484

Browse files
stepangoClaw
andauthored
F-072: navigationRes Path B + deprecate withPlugin chain (#189)
* F-072: mark in_progress * F-072: navigationRes Path B + deprecate withPlugin chain Migrate sample navigation off .withPlugin onto a Path B derived type (navigationRes) with type-owned safe-args. Shared resourcesTarget helper; androidRes/binary/uiLibrary return Unit; deprecate TargetBuilder, PluginWrapper, and sample Plugins factories. --------- Co-authored-by: Claw <claw@Claws-MacBook-Pro.local>
1 parent bcd2509 commit 687f484

14 files changed

Lines changed: 173 additions & 42 deletions

File tree

TICKETS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ Close the biggest call-site / multi-way gap: chain `withPlugin`. Design:
9292
|----|--------|-------|-------|
9393
| F-070 | done | Design type-owned plugins API | Bazel north star; type owns plugin; auto-apply; reject free-form lists + call-site binding re-selection |
9494
| F-071 | done | **Implement** type→plugin registry + auto-apply; `targetPlugin` / `deriveTargetType` | `TargetPluginSpec` + registry + Path A/B; `applyTargetPlugins` on all Android DSLs; unit tests; plugins build green; legacy shims kept for F-072 |
95-
| F-072 | todo | Migrate sample to derived types (e.g. `navigationRes`); hard-deprecate chain | Zero `.withPlugin` in tree; `TargetBuilder`/`PluginWrapper` `@Deprecated` or removed; application green |
95+
| F-072 | done | Migrate sample to derived types (e.g. `navigationRes`); hard-deprecate chain | Path B `navigationRes` in build-dependencies; `resourcesTarget` helper; Unit returns on androidRes/binary/uiLibrary; `TargetBuilder`/`PluginWrapper`/`Plugins` `@Deprecated`; zero active `.withPlugin`; application build green |
9696
| F-073 | todo | User docs + progressive example + agent skill; close GH #36 | Call sites attributes-only; registration/type layer documented |
9797

9898
## P8 — Principle alignment (implementation matches goals)

application/binary/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ androidBinary(
2727
)
2828
)
2929
// TODO: enable when create crashlytics project
30-
// .withPlugins(Plugins.googleServices, Plugins.crashlytics())
30+
// (would be a derived firebaseBinary type per Path B, not .withPlugins chain)
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// Navigation graphs only — resources target (flat structure, not androidLibrary).
2-
androidRes(
2+
// Uses Path B derived type (F-072) so safe-args is owned by the type, not call-site chain.
3+
navigationRes(
34
packageName = "tools.forma.sample.core.navigation.library",
45
dependencies = deps(
56
androidx.navigation
67
)
7-
).withPlugin(Plugins.navigationSafeArgs)
8+
)

build-dependencies/dependencies/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ dependencies {
88
implementation("tools.forma:deps")
99
implementation("tools.forma:owners")
1010
implementation("tools.forma:config")
11+
// F-072: Path B derived types (navigationRes) need android DSL helpers + TargetType on compile classpath
12+
implementation("tools.forma:android")
13+
implementation("tools.forma:core")
1114

1215
implementation("com.google.firebase:firebase-crashlytics-gradle:2.9.5")
1316
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import org.gradle.api.Project
2+
import tools.forma.android.target.AndroidTargetTypes
3+
import tools.forma.android.target.deriveTargetType
4+
import tools.forma.android.target.targetPlugin
5+
import tools.forma.android.visibility.Public
6+
import tools.forma.android.visibility.Visibility
7+
import tools.forma.deps.core.FormaDependency
8+
import tools.forma.owners.NoOwner
9+
import tools.forma.owners.Owner
10+
11+
// F-072: Sample Path B derived target for modules that need the safe-args plugin.
12+
// Registered at class load (before call sites execute) via top-level val.
13+
// nameSuffix kept as "res" so SuffixNameMatcher + existing consumers continue to work
14+
// without touching the dependency matrix or directory names.
15+
private val navigationSafeArgs = targetPlugin(id = "androidx.navigation.safeargs.kotlin")
16+
17+
val NavigationResType = deriveTargetType(
18+
id = "sample.navigation-res",
19+
base = AndroidTargetTypes.res,
20+
nameSuffix = "res",
21+
plugins = listOf(navigationSafeArgs),
22+
)
23+
24+
/**
25+
* Resources target that carries the androidx.navigation.safeargs.kotlin plugin (Path B).
26+
* Call sites are Bazel-flat: only attributes, no plugin ids.
27+
*
28+
* Delegates to [resourcesTarget] with [NavigationResType] so type-owned plugins auto-apply.
29+
*/
30+
fun Project.navigationRes(
31+
packageName: String,
32+
owner: Owner = NoOwner,
33+
visibility: Visibility = Public,
34+
dependencies: FormaDependency = emptyDependency(),
35+
manifestPlaceholders: Map<String, Any> = emptyMap()
36+
) {
37+
resourcesTarget(
38+
type = NavigationResType,
39+
packageName = packageName,
40+
owner = owner,
41+
visibility = visibility,
42+
dependencies = dependencies,
43+
manifestPlaceholders = manifestPlaceholders,
44+
)
45+
}

build-dependencies/dependencies/src/main/kotlin/Plugins.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,27 @@ import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsExtension
22
import tools.forma.deps.core.PluginWrapper
33
import tools.forma.deps.core.pluginConfiguration
44

5+
/**
6+
* Legacy PluginWrapper factories for the old .withPlugin chain API.
7+
* @deprecated F-072: sample now uses Path B derived types (navigationRes etc).
8+
* New usage: targetPlugin(id) + deriveTargetType(...) (see docs/TARGET-PLUGINS.md).
9+
* These remain only for transitional references / docs examples.
10+
*/
11+
@Deprecated(
12+
message = "Plugins.* are for the deprecated .withPlugin chain. Prefer type-owned plugins (deriveTargetType / registerTargetPlugin).",
13+
level = DeprecationLevel.WARNING
14+
)
515
object Plugins {
616

17+
@Deprecated("Use navigationRes derived type (Path B) instead of .withPlugin(Plugins.navigationSafeArgs)", ReplaceWith("/* navigationRes(...) */"), DeprecationLevel.WARNING)
718
val navigationSafeArgs: PluginWrapper<Any> = PluginWrapper(
819
"androidx.navigation.safeargs.kotlin"
920
)
1021

22+
@Deprecated("Firebase plugins would use a derived firebase* type, not chain", level = DeprecationLevel.WARNING)
1123
val googleServices = PluginWrapper<Any>("com.google.gms.google-services")
1224

25+
@Deprecated("Firebase plugins would use a derived firebase* type, not chain", level = DeprecationLevel.WARNING)
1326
fun crashlytics(mappingFileUploadEnabled: Boolean = false) = PluginWrapper(
1427
"com.google.firebase.crashlytics",
1528
google.firebase,

docs/PROGRESS.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@
22

33
Newest entries first.
44

5+
## 2026-07-19 — F-072: navigationRes Path B + deprecate withPlugin chain
6+
7+
- **Ticket:** F-072 → `done`
8+
- **Branch / PR:** `forma/F-072-navigation-res` → base `v2`
9+
- **Skills/modes:** Grok Build `--mode full` (design + implement max-turns); Hermes finish path: `resourcesTarget` helper, core classpath fix, verify builds, bookkeeping
10+
- **Code:**
11+
- `plugins/android`: `resourcesTarget(type, …)` shared res wiring; `androidRes` / `androidBinary` / `uiLibrary` return **Unit**; `TargetBuilder` `@Deprecated`
12+
- `plugins/deps`: `PluginWrapper` `@Deprecated`
13+
- `build-dependencies`: `NavigationRes.kt``deriveTargetType(sample.navigation-res, base=res, suffix=res)` + `navigationRes(...)` DSL; deps on `tools.forma:android` + `:core`; legacy `Plugins` object `@Deprecated`
14+
- Sample: `application/core/navigation/res``navigationRes(...)` (no plugin ids); binary comment updated (no chain)
15+
- **Verify (real host, `source scripts/env-mac.sh`):**
16+
- `plugins/ ./gradlew :deps:test :android:compileKotlin build`**BUILD SUCCESSFUL**
17+
- `application/ ./gradlew :core-navigation-res:compileDebugKotlin`**SUCCESS** including `generateSafeArgsDebug` (type-owned safe-args applied)
18+
- `application/ ./gradlew build`**BUILD SUCCESSFUL** (2554 tasks)
19+
- `rg` active `.withPlugin` call sites → **none** (only deprecation messages / TestKit `withPluginClasspath`)
20+
- **Blockers:** none
21+
- **Next:** F-073 user docs + progressive example + agent skill; close GH #36
22+
523
## 2026-07-19 — F-071: type-owned target plugins registry + auto-apply
624

725
- **Ticket:** F-071 → `done`

docs/TARGET-PLUGINS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ target kind + attributes. Plugin identity is part of the **rule / target type**,
77
not restated on every module. Extending a type with a plugin **auto-applies** that
88
plugin on every call site of that type.
99

10-
**Status:** F-070 design accepted (3rd revision). **F-071 implemented** (type→plugin registry + auto-apply).
11-
**Remaining:** F-072 sample migrate / deprecate chain · F-073 docs / GH #36.
10+
**Status:** F-070 design accepted · **F-071** registry + auto-apply · **F-072** sample `navigationRes` Path B + chain `@Deprecated`.
11+
**Remaining:** F-073 docs / progressive example / GH #36.
1212

1313
**Related:** [`DEPS-CATALOG.md`](DEPS-CATALOG.md), [`ARCHITECTURE.md`](ARCHITECTURE.md),
1414
[`forma-core-api.md`](forma-core-api.md), `TargetRegistry` / `TargetRegistration`.

plugins/android/src/main/java/TargetBuilder.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
import org.gradle.api.Project
22
import tools.forma.deps.core.PluginWrapper
33

4+
/**
5+
* @deprecated Chain API for external plugins. The target **type** owns plugins.
6+
* Use [deriveTargetType] + [registerTargetPlugin] (or Path B derived DSLs such as
7+
* navigationRes in sample) so call sites stay attributes-only.
8+
* See docs/TARGET-PLUGINS.md
9+
*/
10+
@Deprecated(
11+
message = "TargetBuilder chain removed. Plugin identity belongs to the TargetType via deriveTargetType / registerTargetPlugin. Call sites must be Bazel-flat. See docs/TARGET-PLUGINS.md",
12+
replaceWith = ReplaceWith("/* navigationRes(...) or androidRes(...) after type registration; no .withPlugin */"),
13+
level = DeprecationLevel.WARNING
14+
)
415
class TargetBuilder(
516
private val project: Project
617
) {
718

19+
@Deprecated("Use type-owned plugins", ReplaceWith("/* see docs/TARGET-PLUGINS.md */"), DeprecationLevel.WARNING)
820
fun withPlugin(pluginWrapper: PluginWrapper<*>): TargetBuilder {
921
pluginWrapper(project)
1022
return this
1123
}
1224

25+
@Deprecated("Use type-owned plugins", ReplaceWith("/* see docs/TARGET-PLUGINS.md */"), DeprecationLevel.WARNING)
1326
fun withPlugins(vararg pluginWrappers: PluginWrapper<*>): TargetBuilder {
1427
pluginWrappers.forEach { withPlugin(it) }
1528
return this

plugins/android/src/main/java/androidBinary.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fun Project.androidBinary(
4141
manifestPlaceholders: Map<String, Any> = emptyMap(),
4242
/** Enable Jetpack Compose; defaults to project-wide `compose` setting. */
4343
compose: Boolean = Forma.settings.compose,
44-
): TargetBuilder {
44+
) {
4545

4646
disallowResources()
4747

@@ -67,6 +67,5 @@ fun Project.androidBinary(
6767
validator = AndroidTargetRegistry.validatorFor(AndroidTargetTypes.binary).asValidator(),
6868
dependencies = dependencies
6969
)
70-
71-
return TargetBuilder(this)
70+
// Unit return (no TargetBuilder chain after F-072)
7271
}

0 commit comments

Comments
 (0)