You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(codegen): add codegen scopes (object/package/app) to the concepts guide
Captures the scope axis from the Java codegen scope investigation: object scope
(perEntity) and app scope (oncePerRun, e.g. PlantUML whole-model diagram / Kotlin
Spring @configuration / a global registry) are first-class; package scope is the gap
(Java did it ad-hoc via getPackage() grouping; we make perPackage first-class). The
scope IS the walk — what the generator iterates over.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LuZWKnWzYGVnESijL7uuky
Copy file name to clipboardExpand all lines: docs/features/codegen-concepts.md
+37Lines changed: 37 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -116,3 +116,40 @@ C#, Spring for Java/Kotlin, Pydantic for Python) — collapsing them to one gene
116
116
emitter is the OpenAPI-Generator trap. Keep language-*neutral* artifacts (migrations,
117
117
docs, future OpenAPI/Mermaid) as **one shared engine**. The test: does the output depend
118
118
on the implementation language? If yes, it's per-port; if no, it's shared. (ADR-0020.)
119
+
120
+
## 10. Codegen scopes — object, package, app
121
+
122
+
MetaObjects codegen has been object-centric (one artifact per MetaObject), but
123
+
generation has three natural scopes, and all three are legitimate first-class
124
+
patterns. **The scope *is* the walk** — what the generator iterates over:
125
+
126
+
| Scope | Walks | Emits | Examples |
127
+
|---|---|---|---|
128
+
|**Object**| each MetaObject | one artifact per object | entity, queries, routes, DTO, repository |
129
+
|**Package**| each package (objects grouped by package) | one artifact per package | a service-layer module, a package barrel/index, a package-scoped registry or config |
130
+
|**App**| the whole model once | one artifact for the app | a shared component, an app-wide config (e.g. a Spring `@Configuration`), a global object/binding registry, the overall barrel, a whole-model diagram |
131
+
132
+
**Lineage (the Java predecessor).** App-level generation was first-class there —
133
+
`SingleFileDirectGeneratorBase` (one whole-model PlantUML diagram), or overriding
134
+
`execute(loader)` to emit a single app config (`KotlinSpringConfigGenerator`), or the
135
+
`getFinalWriter()` hook (per-object files *plus* one final app file). Package-level
136
+
was *not* first-class even there — it was done ad-hoc, grouping by `getPackage()`
137
+
inside a generator's `execute()` (the FR-019 shared-enum aggregation). The newest,
138
+
cleanest shape is the cross-port `TemplateGenerator`'s caller-supplied **`walk`
139
+
function**: the walk returns the units to render, so per-object / per-package /
140
+
whole-model are just different walks.
141
+
142
+
**The model to expose.** Three scope helpers, so the scope is declared, not buried in
143
+
custom iteration:
144
+
145
+
-**`perEntity(fn)`** — object scope. *(exists)*
146
+
-**`perPackage(fn)`** — package scope: group matching objects by package, run `fn`
147
+
once per package. *(the gap — Java never had this cleanly either, so this is an
148
+
improvement on the predecessor, not just parity.)*
149
+
-**`oncePerRun(fn)`** — app scope: run once over all matching objects. *(exists; an
150
+
`appLevel` alias can make the intent explicit.)*
151
+
152
+
A generator picks its scope by which helper it composes — the same way it picks
153
+
object vs run today. Reference templates and the guidance call out the scope each
154
+
starting point is for, so "I need a per-package service layer" maps to a clear
0 commit comments