@zio.dev/zio-blocks 0.0.33 → 0.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/guides/compile-time-resource-safety-with-scope.md +16 -17
  2. package/guides/getting-started-with-mux.md +1507 -0
  3. package/guides/query-dsl-extending.md +161 -102
  4. package/guides/query-dsl-fluent-builder.md +217 -157
  5. package/guides/query-dsl-reified-optics.md +12 -10
  6. package/guides/query-dsl-sql.md +246 -165
  7. package/guides/telemetry-guide.md +1069 -0
  8. package/guides/zio-schema-migration.md +29 -22
  9. package/index.md +292 -50
  10. package/package.json +1 -1
  11. package/plans/config-follow-up-prs.md +188 -0
  12. package/plans/config-pr-assessment-roadmap.md +310 -0
  13. package/reference/MuxDataFlow.jsx +250 -0
  14. package/reference/async.md +651 -0
  15. package/reference/chunk.md +3533 -308
  16. package/reference/codegen/case-class.md +436 -0
  17. package/reference/codegen/emitter-config.md +383 -0
  18. package/reference/codegen/examples.md +664 -0
  19. package/reference/codegen/field.md +316 -0
  20. package/reference/codegen/index.md +317 -0
  21. package/reference/codegen/scala-emitter.md +392 -0
  22. package/reference/codegen/scala-file.md +276 -0
  23. package/reference/codegen/sealed-trait.md +408 -0
  24. package/reference/codegen/type-definition.md +340 -0
  25. package/reference/codegen/type-ref.md +201 -0
  26. package/reference/combinators.md +347 -117
  27. package/reference/config.md +158 -0
  28. package/reference/context.md +4 -4
  29. package/reference/datastar.md +346 -0
  30. package/reference/docs.md +1461 -345
  31. package/reference/endpoint/auth-type.md +146 -0
  32. package/reference/endpoint/endpoint.md +297 -0
  33. package/reference/endpoint/http-codec.md +249 -0
  34. package/reference/endpoint/index.md +825 -0
  35. package/reference/endpoint/path-codec.md +237 -0
  36. package/reference/endpoint/route-pattern.md +196 -0
  37. package/reference/endpoint/route-tree.md +111 -0
  38. package/reference/endpoint/segment-codec.md +212 -0
  39. package/reference/html.md +1120 -0
  40. package/reference/htmx/attribute-values.md +359 -0
  41. package/reference/htmx/hx-encoding.md +111 -0
  42. package/reference/htmx/hx-params.md +204 -0
  43. package/reference/htmx/hx-swap.md +276 -0
  44. package/reference/htmx/hx-sync.md +251 -0
  45. package/reference/htmx/hx-target.md +314 -0
  46. package/reference/htmx/hx-trigger.md +457 -0
  47. package/reference/htmx/hx-url-update.md +239 -0
  48. package/reference/htmx/index.md +855 -0
  49. package/reference/http-model/index.md +47 -0
  50. package/reference/http-model/model.md +1481 -0
  51. package/reference/http-model/schema.md +747 -0
  52. package/reference/maybe.md +826 -0
  53. package/reference/media-type.md +2 -2
  54. package/reference/mux.mdx +823 -0
  55. package/reference/openapi.md +1351 -0
  56. package/reference/resource-management/defer-handle.md +1 -1
  57. package/reference/resource-management/resource.md +31 -2
  58. package/reference/resource-management/scope.md +28 -12
  59. package/reference/resource-management/wire.md +3 -7
  60. package/reference/ringbuffer/MpmcDiagram.jsx +717 -0
  61. package/reference/ringbuffer/MpscDiagram.jsx +618 -0
  62. package/reference/ringbuffer/SpmcDiagram.jsx +680 -0
  63. package/reference/ringbuffer/SpscDiagram.jsx +677 -0
  64. package/reference/ringbuffer/advanced.mdx +109 -0
  65. package/reference/ringbuffer/index.mdx +145 -0
  66. package/reference/ringbuffer/mpmc.mdx +151 -0
  67. package/reference/ringbuffer/mpsc.mdx +132 -0
  68. package/reference/ringbuffer/spmc.mdx +108 -0
  69. package/reference/ringbuffer/spsc.mdx +344 -0
  70. package/reference/{allows.md → schema/allows.md} +4 -4
  71. package/reference/{binding-resolver.md → schema/binding-resolver.md} +1 -1
  72. package/reference/{binding.md → schema/binding.md} +2 -3
  73. package/reference/schema/built-in-codecs/avro.md +451 -0
  74. package/reference/schema/built-in-codecs/bson.md +480 -0
  75. package/reference/schema/built-in-codecs/csv.md +564 -0
  76. package/reference/schema/built-in-codecs/index.md +77 -0
  77. package/reference/schema/built-in-codecs/json/index.md +295 -0
  78. package/reference/schema/built-in-codecs/json/json-config.md +217 -0
  79. package/reference/{json-patch.md → schema/built-in-codecs/json/json-patch.md} +5 -5
  80. package/reference/{json-schema.md → schema/built-in-codecs/json/json-schema.md} +14 -47
  81. package/reference/schema/built-in-codecs/json/json-selection.md +322 -0
  82. package/reference/{json.md → schema/built-in-codecs/json/json.md} +32 -64
  83. package/reference/schema/built-in-codecs/messagepack.md +508 -0
  84. package/reference/schema/built-in-codecs/thrift.md +433 -0
  85. package/reference/schema/built-in-codecs/toon.md +1078 -0
  86. package/reference/{xml.md → schema/built-in-codecs/xml.md} +13 -9
  87. package/reference/schema/built-in-codecs/yaml.md +552 -0
  88. package/reference/{codec.md → schema/codec.md} +10 -10
  89. package/reference/{dynamic-optic.md → schema/dynamic-optic.md} +151 -5
  90. package/reference/{dynamic-schema.md → schema/dynamic-schema.md} +8 -8
  91. package/reference/schema/format.md +92 -0
  92. package/reference/schema/index.md +50 -0
  93. package/reference/schema/migration.md +297 -0
  94. package/reference/{modifier.md → schema/modifier.md} +58 -7
  95. package/reference/{optics.md → schema/optics.md} +2 -2
  96. package/reference/{patch.md → schema/patch.md} +1 -1
  97. package/{path-interpolator.md → reference/schema/path-interpolator.md} +165 -72
  98. package/reference/{schema-evolution → schema/schema-evolution}/as.md +8 -8
  99. package/reference/{schema-evolution → schema/schema-evolution}/index.md +2 -2
  100. package/reference/{schema-evolution → schema/schema-evolution}/into.md +8 -8
  101. package/reference/{schema-expr.md → schema/schema-expr.md} +110 -175
  102. package/reference/{schema.md → schema/schema.md} +12 -0
  103. package/reference/{structural-types.md → schema/structural-types.md} +1 -1
  104. package/reference/{type-class-derivation.md → schema/type-class-derivation.md} +63 -1
  105. package/reference/smithy.md +533 -0
  106. package/reference/sql/db-codec-deriver.md +71 -0
  107. package/reference/sql/db-codec.md +687 -0
  108. package/reference/sql/db-con.md +271 -0
  109. package/reference/sql/db-connection.md +153 -0
  110. package/reference/sql/db-param-writer.md +77 -0
  111. package/reference/sql/db-param.md +66 -0
  112. package/reference/sql/db-result-reader.md +146 -0
  113. package/reference/sql/db-tx.md +82 -0
  114. package/reference/sql/db-value.md +41 -0
  115. package/reference/sql/ddl.md +85 -0
  116. package/reference/sql/frag.md +254 -0
  117. package/reference/sql/index.md +341 -0
  118. package/reference/sql/repo.md +600 -0
  119. package/reference/sql/sql-dialect.md +73 -0
  120. package/reference/sql/sql-logger.md +62 -0
  121. package/reference/sql/sql-name-mapper.md +70 -0
  122. package/reference/sql/table-metadata.md +134 -0
  123. package/reference/sql/table.md +448 -0
  124. package/reference/sql/transactor-zio.md +399 -0
  125. package/reference/sql/transactor.md +353 -0
  126. package/reference/sql-zio.md +112 -0
  127. package/reference/streams/concurrent-operators.md +106 -0
  128. package/reference/streams/index.md +653 -0
  129. package/reference/streams/pipeline.md +718 -0
  130. package/reference/streams/reader.md +1284 -0
  131. package/reference/streams/scala-2-compatibility.md +55 -0
  132. package/reference/streams/sink.md +1426 -0
  133. package/reference/streams/stream.md +2526 -0
  134. package/reference/streams/writer.md +1045 -0
  135. package/reference/streams/zero-boxing.md +275 -0
  136. package/reference/telemetry.md +693 -0
  137. package/reference/typeid.md +5 -19
  138. package/sidebars.js +238 -43
  139. package/reference/formats.md +0 -694
  140. package/reference/http-model.md +0 -1716
  141. package/reference/streams.md +0 -989
  142. package/ringbuffer.md +0 -249
  143. /package/reference/{json-differ.md → schema/built-in-codecs/json/json-differ.md} +0 -0
  144. /package/reference/{dynamic-value.md → schema/dynamic-value.md} +0 -0
  145. /package/reference/{lazy.md → schema/lazy.md} +0 -0
  146. /package/reference/{reflect.md → schema/reflect.md} +0 -0
  147. /package/reference/{registers.md → schema/registers.md} +0 -0
  148. /package/reference/{schema-error.md → schema/schema-error.md} +0 -0
  149. /package/reference/{syntax.md → schema/syntax.md} +0 -0
  150. /package/reference/{validation.md → schema/validation.md} +0 -0
@@ -0,0 +1,316 @@
1
+ ---
2
+ id: field
3
+ title: "Field"
4
+ ---
5
+
6
+ `Field` represents a class field (constructor parameter) in the IR. Combine a name with a type reference, optionally adding default values and modifiers.
7
+
8
+ ## Use Cases
9
+
10
+ - Defining constructor parameters for case classes
11
+ - Specifying fields in abstract classes
12
+ - Modeling data structure fields with optional defaults
13
+
14
+ ## Construction
15
+
16
+ Build a field with a name and type:
17
+
18
+ ```scala
19
+ import zio.blocks.codegen.ir._
20
+
21
+ val id = Field("id", TypeRef.Long)
22
+ val name = Field("name", TypeRef.String)
23
+ val email = Field("email", TypeRef.optional(TypeRef.String))
24
+ ```
25
+
26
+ With default value:
27
+
28
+ ```scala
29
+ import zio.blocks.codegen.ir._
30
+
31
+ val timeout = Field("timeout", TypeRef.Long, defaultValue = Some("5000L"))
32
+ val retries = Field("retries", TypeRef.Int, defaultValue = Some("3"))
33
+ ```
34
+
35
+ With annotations:
36
+
37
+ ```scala
38
+ import zio.blocks.codegen.ir._
39
+
40
+ val annotated = Field(
41
+ "id",
42
+ TypeRef.Long,
43
+ annotations = List(Annotation("id"))
44
+ )
45
+ ```
46
+
47
+ ## Key Operations
48
+
49
+ All `Field` instances support these operations:
50
+
51
+ ### Accessing Components
52
+
53
+ Extract parts of a field:
54
+
55
+ ```scala
56
+ import zio.blocks.codegen.ir._
57
+
58
+ val field = Field("age", TypeRef.Int, defaultValue = Some("0"))
59
+ ```
60
+
61
+ View field properties:
62
+
63
+ ```scala
64
+ import zio.blocks.codegen.ir._
65
+
66
+ field.name // "age"
67
+ // res4: String = "age"
68
+ field.typeRef // TypeRef.Int
69
+ // res5: TypeRef = TypeRef(name = "Int", typeArgs = List())
70
+ field.defaultValue // Some("0")
71
+ // res6: Option[String] = Some("0")
72
+ field.annotations // List[Annotation]
73
+ // res7: List[Annotation] = List()
74
+ ```
75
+
76
+ ### Building with Copy
77
+
78
+ Modify a field using copy:
79
+
80
+ ```scala
81
+ import zio.blocks.codegen.ir._
82
+
83
+ val field = Field("age", TypeRef.Int, defaultValue = Some("0"))
84
+ ```
85
+
86
+ Apply modifications:
87
+
88
+ ```scala
89
+ import zio.blocks.codegen.ir._
90
+
91
+ val updated = field.copy(
92
+ defaultValue = Some("18"),
93
+ annotations = List(Annotation("min"))
94
+ )
95
+ // updated: Field = Field(
96
+ // name = "age",
97
+ // typeRef = TypeRef(name = "Int", typeArgs = List()),
98
+ // defaultValue = Some("18"),
99
+ // annotations = List(Annotation(name = "min", args = List())),
100
+ // doc = None
101
+ // )
102
+ ```
103
+
104
+ ## Examples
105
+
106
+ These examples show practical usage patterns for `Field`:
107
+
108
+ ### Example 1: Simple Fields
109
+
110
+ Create fields for a case class:
111
+
112
+ ```scala
113
+ import zio.blocks.codegen.ir._
114
+ import zio.blocks.codegen.emit._
115
+
116
+ val order = CaseClass(
117
+ name = "Order",
118
+ fields = List(
119
+ Field("id", TypeRef.Long),
120
+ Field("customerId", TypeRef.String),
121
+ Field("total", TypeRef("BigDecimal")),
122
+ Field("status", TypeRef.String)
123
+ )
124
+ )
125
+
126
+ val file = ScalaFile(
127
+ packageDecl = PackageDecl("com.shop"),
128
+ types = List(order)
129
+ )
130
+ ```
131
+
132
+ Emits:
133
+
134
+ ```scala
135
+ import zio.blocks.codegen.emit._
136
+
137
+ ScalaEmitter.emit(file, EmitterConfig())
138
+ // res10: String = """package com.shop
139
+ //
140
+ // case class Order(
141
+ // id: Long,
142
+ // customerId: String,
143
+ // total: BigDecimal,
144
+ // status: String,
145
+ // )
146
+ // """
147
+ ```
148
+
149
+ ### Example 2: Fields with Defaults
150
+
151
+ Case class fields with default values:
152
+
153
+ ```scala
154
+ import zio.blocks.codegen.ir._
155
+ import zio.blocks.codegen.emit._
156
+
157
+ val config = CaseClass(
158
+ name = "DatabaseConfig",
159
+ fields = List(
160
+ Field("host", TypeRef.String, defaultValue = Some("\"localhost\"")),
161
+ Field("port", TypeRef.Int, defaultValue = Some("5432")),
162
+ Field("timeout", TypeRef.Long, defaultValue = Some("30000L"))
163
+ )
164
+ )
165
+
166
+ val file = ScalaFile(
167
+ packageDecl = PackageDecl("com.example"),
168
+ types = List(config)
169
+ )
170
+ ```
171
+
172
+ Emits:
173
+
174
+ ```scala
175
+ import zio.blocks.codegen.emit._
176
+
177
+ ScalaEmitter.emit(file, EmitterConfig())
178
+ // res12: String = """package com.example
179
+ //
180
+ // case class DatabaseConfig(
181
+ // host: String = "localhost",
182
+ // port: Int = 5432,
183
+ // timeout: Long = 30000L,
184
+ // )
185
+ // """
186
+ ```
187
+
188
+ ### Example 3: Optional and Collection Fields
189
+
190
+ Fields with generic types:
191
+
192
+ ```scala
193
+ import zio.blocks.codegen.ir._
194
+ import zio.blocks.codegen.emit._
195
+
196
+ val article = CaseClass(
197
+ name = "Article",
198
+ fields = List(
199
+ Field("title", TypeRef.String),
200
+ Field("content", TypeRef.String),
201
+ Field("author", TypeRef.optional(TypeRef.String)),
202
+ Field("tags", TypeRef.list(TypeRef.String)),
203
+ Field("metadata", TypeRef.map(TypeRef.String, TypeRef.String))
204
+ )
205
+ )
206
+
207
+ val file = ScalaFile(
208
+ packageDecl = PackageDecl("com.example"),
209
+ types = List(article)
210
+ )
211
+ ```
212
+
213
+ Emits:
214
+
215
+ ```scala
216
+ import zio.blocks.codegen.emit._
217
+
218
+ ScalaEmitter.emit(file, EmitterConfig())
219
+ // res14: String = """package com.example
220
+ //
221
+ // case class Article(
222
+ // title: String,
223
+ // content: String,
224
+ // author: Option[String],
225
+ // tags: List[String],
226
+ // metadata: Map[String, String],
227
+ // )
228
+ // """
229
+ ```
230
+
231
+ ### Example 4: Nested Generic Types
232
+
233
+ Complex field types:
234
+
235
+ ```scala
236
+ import zio.blocks.codegen.ir._
237
+ import zio.blocks.codegen.emit._
238
+
239
+ val response = CaseClass(
240
+ name = "Response",
241
+ fields = List(
242
+ Field(
243
+ "data",
244
+ TypeRef("Option", List(
245
+ TypeRef("List", List(TypeRef.String))
246
+ ))
247
+ ),
248
+ Field(
249
+ "errors",
250
+ TypeRef("List", List(
251
+ TypeRef("Map", List(TypeRef.String, TypeRef.String))
252
+ ))
253
+ )
254
+ )
255
+ )
256
+
257
+ val file = ScalaFile(
258
+ packageDecl = PackageDecl("com.example"),
259
+ types = List(response)
260
+ )
261
+ ```
262
+
263
+ Emits:
264
+
265
+ ```scala
266
+ import zio.blocks.codegen.emit._
267
+
268
+ ScalaEmitter.emit(file, EmitterConfig())
269
+ // res16: String = """package com.example
270
+ //
271
+ // case class Response(
272
+ // data: Option[List[String]],
273
+ // errors: List[Map[String, String]],
274
+ // )
275
+ // """
276
+ ```
277
+
278
+ ### Example 5: Fields with Type Parameters
279
+
280
+ Fields using generic type variables:
281
+
282
+ ```scala
283
+ import zio.blocks.codegen.ir._
284
+ import zio.blocks.codegen.emit._
285
+
286
+ val page = CaseClass(
287
+ name = "Page",
288
+ fields = List(
289
+ Field("items", TypeRef("List", List(TypeRef("T")))),
290
+ Field("total", TypeRef.Long),
291
+ Field("pageSize", TypeRef.Int)
292
+ ),
293
+ typeParams = List(TypeParam("T"))
294
+ )
295
+
296
+ val file = ScalaFile(
297
+ packageDecl = PackageDecl("com.example"),
298
+ types = List(page)
299
+ )
300
+ ```
301
+
302
+ Emits:
303
+
304
+ ```scala
305
+ import zio.blocks.codegen.emit._
306
+
307
+ ScalaEmitter.emit(file, EmitterConfig())
308
+ // res18: String = """package com.example
309
+ //
310
+ // case class Page[T](
311
+ // items: List[T],
312
+ // total: Long,
313
+ // pageSize: Int,
314
+ // )
315
+ // """
316
+ ```
@@ -0,0 +1,317 @@
1
+ ---
2
+ id: index
3
+ title: "Code Generation"
4
+ ---
5
+
6
+ `zio-blocks-codegen` is a **generic, domain-agnostic Scala code generation library**. It provides an intermediate representation (IR) for building type-safe models of Scala code structures, and a pure emitter that generates well-formatted Scala source files from those models.
7
+
8
+ Core types: `ScalaFile`, `TypeDefinition`, `CaseClass`, `SealedTrait`, `Enum`, `Field`, `TypeRef`, `Method`, `Annotation`.
9
+
10
+ Here's the structure of two core types:
11
+
12
+ ```scala
13
+ // IR models the structure of Scala code
14
+ case class ScalaFile(
15
+ packageDecl: PackageDecl,
16
+ imports: List[Import] = Nil,
17
+ types: List[TypeDefinition] = Nil
18
+ )
19
+
20
+ case class CaseClass(
21
+ name: String,
22
+ fields: List[Field],
23
+ typeParams: List[TypeParam] = Nil,
24
+ derives: List[String] = Nil,
25
+ // ...
26
+ )
27
+ ```
28
+
29
+ ## Introduction
30
+
31
+ This module is designed to be a **reusable building block** for any tool that needs to generate Scala code—whether from OpenAPI specifications, Smithy models, Protocol Buffers, JSON Schema, or any other source format.
32
+
33
+ Rather than embedding code generation logic into domain-specific tools, you model your source data in the codegen IR, then emit clean, formatted Scala. This separation enables single source of truth, consistency, and reuse across all generators without cross-coupling.
34
+
35
+ ## Motivation
36
+
37
+ Codegen IR exists to solve a specific problem: **many generators produce the same output (Scala code) but reinvent the emission logic.** Before `zio-blocks-codegen`, each generator (OpenAPI, Smithy, Protobuf, etc.) had its own IR and emitter, leading to duplication, bugs, and inconsistency. By extracting IR and emitter into `zio-blocks-codegen`, all generators share one implementation.
38
+
39
+ Before `zio-blocks-codegen`, each generator had its own IR and emitter:
40
+
41
+ ```
42
+ OpenAPI → Scala Smithy → Scala Protobuf → Scala
43
+ ↓ ↓ ↓
44
+ [Custom IR] [Custom IR] [Custom IR]
45
+ ↓ ↓ ↓
46
+ [Custom Emitter] [Custom Emitter] [Custom Emitter]
47
+ ↓ ↓ ↓
48
+ Scala Code Scala Code Scala Code
49
+
50
+ ❌ Duplication: Same problem solved 3 times with different code
51
+ ❌ Bugs: Fixes in one place don't help others
52
+ ❌ Inconsistency: Different styles, formatting, edge cases
53
+ ```
54
+
55
+ Now with `zio-blocks-codegen`, all generators converge on a single implementation:
56
+
57
+ ```
58
+ OpenAPI → Scala Smithy → Scala Protobuf → Scala JSON Schema → Scala
59
+ ↓ ↓ ↓ ↓
60
+ └──────────────────┬───────────────────┘────────────────────┘
61
+ ↓
62
+ [zio-blocks-codegen]
63
+ ↓
64
+ ┌──────────┴──────────┐
65
+ ↓ ↓
66
+ [IR: Type-safe] [Emitter: Pure function]
67
+ representation (no side effects)
68
+ of Scala code |
69
+ ↓ ↓
70
+ └──────────┬──────────┘
71
+ ↓
72
+ Scala Code
73
+
74
+ ✅ Single source of truth: One well-tested implementation
75
+ ✅ Consistency: All generators use the same emitter
76
+ ✅ Reusability: Zero coupling between domain-specific tools
77
+ ```
78
+
79
+ ## Installation
80
+
81
+ Add the library to your project:
82
+
83
+ ```scala
84
+ libraryDependencies += "dev.zio" %% "zio-blocks-codegen" % "0.0.51"
85
+ ```
86
+
87
+ Supported Scala versions: 2.13.x and 3.x
88
+
89
+ ## Overview
90
+
91
+ The module has two key layers:
92
+ 1. **IR Layer**: Immutable, strongly-typed models of Scala code structures (files, types, members)
93
+ 2. **Emit Layer**: Pure functions that convert IR models to formatted Scala source code
94
+
95
+ ### IR Layer (`zio.blocks.codegen.ir`)
96
+
97
+ The intermediate representation captures the essential structure of Scala code:
98
+
99
+ - **File structure**: `ScalaFile`, `PackageDecl`, `Import`
100
+ - **Type definitions**: `CaseClass`, `SealedTrait`, `Trait`, `AbstractClass`, `Enum`, `ObjectDef`, `OpaqueType`, `Newtype`, `TypeAlias`
101
+ - **Members**: `Field`, `Method`, `MethodParam`, `Annotation`, `TypeParam`, `TypeRef`
102
+ - **Composition**: Sealed traits like `TypeDefinition`, `SealedTraitCase`, `EnumCase`, `ObjectMember` for modular type safety
103
+
104
+ Each type is **immutable and strongly typed**. You build the IR by composing these types, then hand off to the emitter.
105
+
106
+ ### Emit Layer (`zio.blocks.codegen.emit`)
107
+
108
+ The emitter converts IR to Scala source code:
109
+
110
+ - **`ScalaEmitter`**: Methods to emit any IR node as a formatted string (imports, type definitions, methods, etc.)
111
+ - **`EmitterConfig`**: Configurable formatting (indent width, import sorting, trailing commas, Scala 2 vs. Scala 3 syntax)
112
+ - **No side effects**: Returns strings; your code writes files (or does anything else)
113
+
114
+ ## How They Work Together
115
+
116
+ Here's the typical workflow for a code generator:
117
+
118
+ ```
119
+ 1. Parse source format (OpenAPI, Smithy, etc.)
120
+ ↓
121
+ 2. Build IR models (ScalaFile, CaseClass, SealedTrait, etc.)
122
+ ↓
123
+ 3. Call ScalaEmitter.emit(file, config)
124
+ ↓
125
+ 4. ScalaEmitter returns formatted Scala source as String
126
+ ↓
127
+ 5. Write string to file (or further process it)
128
+ ```
129
+
130
+ Here's an example of building a Scala file with a case class:
131
+
132
+ ```
133
+ ScalaFile
134
+ ├─ packageDecl: PackageDecl("com.example")
135
+ ├─ imports: [Import.WildcardImport("zio")]
136
+ └─ types: [
137
+ CaseClass(
138
+ name = "User",
139
+ fields = [
140
+ Field("id", TypeRef.Long),
141
+ Field("name", TypeRef.String),
142
+ Field("email", TypeRef("Option", List(TypeRef.String)))
143
+ ]
144
+ )
145
+ ]
146
+ ```
147
+
148
+ When you call `ScalaEmitter.emit(file, config)`, it walks this tree and produces:
149
+
150
+ ```scala
151
+ package com.example
152
+
153
+ import zio._
154
+
155
+ case class User(
156
+ id: Long,
157
+ name: String,
158
+ email: Option[String],
159
+ )
160
+ ```
161
+
162
+ The architecture flows through three layers:
163
+
164
+ ```
165
+ ┌──────────────────────────────────────────────────────────┐
166
+ │ Your Generator (OpenAPI, Smithy, Protobuf, JSON Schema) │
167
+ │ - Parse input format │
168
+ │ - Build IR models (CaseClass, SealedTrait, etc.) │
169
+ └────────────────┬─────────────────────────────────────────┘
170
+ │ ScalaFile (root IR node)
171
+ ▼
172
+ ┌──────────────────────────────────────────────────────────┐
173
+ │ zio-blocks-codegen IR Layer │
174
+ │ - TypeDefinition (sealed trait) │
175
+ │ - CaseClass, SealedTrait, Enum, ObjectDef, ... │
176
+ │ - Field, Method, TypeRef, Annotation, TypeParam │
177
+ │ - Strongly typed, immutable, composable │
178
+ └────────────────┬─────────────────────────────────────────┘
179
+ │ IR models
180
+ ▼
181
+ ┌─────────────────────────────────────────────────────────┐
182
+ │ zio-blocks-codegen Emit Layer │
183
+ │ - ScalaEmitter.emit(file, config) → String │
184
+ │ - Supports Scala 3 (enums, derives, * imports) │
185
+ │ - Supports Scala 2 (sealed traits, _ imports, fallback) │
186
+ │ - EmitterConfig: indent, imports, commas, version │
187
+ └────────────────┬────────────────────────────────────────┘
188
+ │ Formatted Scala source
189
+ ▼
190
+ (Write to file or further process)
191
+ ```
192
+
193
+ ## Common Patterns
194
+
195
+ Here are the most common usage patterns:
196
+
197
+ ### Pattern 1: Building a Simple Case Class
198
+
199
+ Build a case class with fields and derive clauses:
200
+
201
+ ```scala
202
+ import zio.blocks.codegen.ir._
203
+
204
+ val user = CaseClass(
205
+ name = "User",
206
+ fields = List(
207
+ Field("id", TypeRef.Long),
208
+ Field("name", TypeRef.String)
209
+ ),
210
+ derives = List("Schema")
211
+ )
212
+ ```
213
+
214
+ ### Pattern 2: Sealed Trait Hierarchies
215
+
216
+ Model ADTs (algebraic data types) as sealed traits with cases:
217
+
218
+ ```scala
219
+ import zio.blocks.codegen.ir._
220
+
221
+ val payment = SealedTrait(
222
+ name = "Payment",
223
+ cases = List(
224
+ SealedTraitCase.CaseClassCase(
225
+ CaseClass(
226
+ "CreditCard",
227
+ List(
228
+ Field("number", TypeRef.String),
229
+ Field("cvv", TypeRef.String)
230
+ )
231
+ )
232
+ ),
233
+ SealedTraitCase.CaseObjectCase("Cash"),
234
+ SealedTraitCase.CaseObjectCase("Check")
235
+ )
236
+ )
237
+ ```
238
+
239
+ ### Pattern 3: Generic Types with Type Parameters
240
+
241
+ Define polymorphic types:
242
+
243
+ ```scala
244
+ import zio.blocks.codegen.ir._
245
+
246
+ val container = CaseClass(
247
+ name = "Container",
248
+ fields = List(
249
+ Field("value", TypeRef("A"))
250
+ ),
251
+ typeParams = List(TypeParam("A"))
252
+ )
253
+ ```
254
+
255
+ ### Pattern 4: Complete File Structure
256
+
257
+ Assemble a complete Scala file ready for emission:
258
+
259
+ ```scala
260
+ import zio.blocks.codegen.ir._
261
+
262
+ val user = CaseClass(
263
+ name = "User",
264
+ fields = List(
265
+ Field("id", TypeRef.Long),
266
+ Field("name", TypeRef.String)
267
+ ),
268
+ derives = List("Schema")
269
+ )
270
+
271
+ val payment = SealedTrait(
272
+ name = "Payment",
273
+ cases = List(
274
+ SealedTraitCase.CaseObjectCase("Cash"),
275
+ SealedTraitCase.CaseObjectCase("Card")
276
+ )
277
+ )
278
+
279
+ val file = ScalaFile(
280
+ packageDecl = PackageDecl("com.example"),
281
+ imports = List(
282
+ Import.WildcardImport("zio"),
283
+ Import.SingleImport("zio.blocks.schema", "Schema")
284
+ ),
285
+ types = List(user, payment)
286
+ )
287
+ ```
288
+
289
+ ## Cross-Scala Compatibility
290
+
291
+ The emitter handles both **Scala 3** and **Scala 2** natively:
292
+
293
+ - **Scala 3 features**: Enums, derives clauses, `*` imports, `as` renames, opaque types
294
+ - **Scala 2 fallback**: Sealed traits, `_` imports, `=>` renames, type aliases
295
+
296
+ You configure the output via `EmitterConfig`:
297
+
298
+ ```scala
299
+ import zio.blocks.codegen.emit._
300
+
301
+ val config = EmitterConfig(
302
+ scala3Syntax = true, // true for Scala 3, false for Scala 2
303
+ indentWidth = 2,
304
+ sortImports = true,
305
+ trailingCommas = true
306
+ )
307
+ ```
308
+
309
+ ## Design Philosophy
310
+
311
+ Three principles guide codegen IR:
312
+
313
+ 1. **Generic**: No domain-specific logic (OpenAPI-specific stuff stays in `zio-blocks-openapi`)
314
+ 2. **Pure**: No side effects—just IR models and string emission
315
+ 3. **Self-contained**: Zero external dependencies, works everywhere
316
+
317
+ This makes it a safe, reliable foundation for any Scala code generator.