@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.
- package/guides/compile-time-resource-safety-with-scope.md +16 -17
- package/guides/getting-started-with-mux.md +1507 -0
- package/guides/query-dsl-extending.md +161 -102
- package/guides/query-dsl-fluent-builder.md +217 -157
- package/guides/query-dsl-reified-optics.md +12 -10
- package/guides/query-dsl-sql.md +246 -165
- package/guides/telemetry-guide.md +1069 -0
- package/guides/zio-schema-migration.md +29 -22
- package/index.md +292 -50
- package/package.json +1 -1
- package/plans/config-follow-up-prs.md +188 -0
- package/plans/config-pr-assessment-roadmap.md +310 -0
- package/reference/MuxDataFlow.jsx +250 -0
- package/reference/async.md +651 -0
- package/reference/chunk.md +3533 -308
- package/reference/codegen/case-class.md +436 -0
- package/reference/codegen/emitter-config.md +383 -0
- package/reference/codegen/examples.md +664 -0
- package/reference/codegen/field.md +316 -0
- package/reference/codegen/index.md +317 -0
- package/reference/codegen/scala-emitter.md +392 -0
- package/reference/codegen/scala-file.md +276 -0
- package/reference/codegen/sealed-trait.md +408 -0
- package/reference/codegen/type-definition.md +340 -0
- package/reference/codegen/type-ref.md +201 -0
- package/reference/combinators.md +347 -117
- package/reference/config.md +158 -0
- package/reference/context.md +4 -4
- package/reference/datastar.md +346 -0
- package/reference/docs.md +1461 -345
- package/reference/endpoint/auth-type.md +146 -0
- package/reference/endpoint/endpoint.md +297 -0
- package/reference/endpoint/http-codec.md +249 -0
- package/reference/endpoint/index.md +825 -0
- package/reference/endpoint/path-codec.md +237 -0
- package/reference/endpoint/route-pattern.md +196 -0
- package/reference/endpoint/route-tree.md +111 -0
- package/reference/endpoint/segment-codec.md +212 -0
- package/reference/html.md +1120 -0
- package/reference/htmx/attribute-values.md +359 -0
- package/reference/htmx/hx-encoding.md +111 -0
- package/reference/htmx/hx-params.md +204 -0
- package/reference/htmx/hx-swap.md +276 -0
- package/reference/htmx/hx-sync.md +251 -0
- package/reference/htmx/hx-target.md +314 -0
- package/reference/htmx/hx-trigger.md +457 -0
- package/reference/htmx/hx-url-update.md +239 -0
- package/reference/htmx/index.md +855 -0
- package/reference/http-model/index.md +47 -0
- package/reference/http-model/model.md +1481 -0
- package/reference/http-model/schema.md +747 -0
- package/reference/maybe.md +826 -0
- package/reference/media-type.md +2 -2
- package/reference/mux.mdx +823 -0
- package/reference/openapi.md +1351 -0
- package/reference/resource-management/defer-handle.md +1 -1
- package/reference/resource-management/resource.md +31 -2
- package/reference/resource-management/scope.md +28 -12
- package/reference/resource-management/wire.md +3 -7
- package/reference/ringbuffer/MpmcDiagram.jsx +717 -0
- package/reference/ringbuffer/MpscDiagram.jsx +618 -0
- package/reference/ringbuffer/SpmcDiagram.jsx +680 -0
- package/reference/ringbuffer/SpscDiagram.jsx +677 -0
- package/reference/ringbuffer/advanced.mdx +109 -0
- package/reference/ringbuffer/index.mdx +145 -0
- package/reference/ringbuffer/mpmc.mdx +151 -0
- package/reference/ringbuffer/mpsc.mdx +132 -0
- package/reference/ringbuffer/spmc.mdx +108 -0
- package/reference/ringbuffer/spsc.mdx +344 -0
- package/reference/{allows.md → schema/allows.md} +4 -4
- package/reference/{binding-resolver.md → schema/binding-resolver.md} +1 -1
- package/reference/{binding.md → schema/binding.md} +2 -3
- package/reference/schema/built-in-codecs/avro.md +451 -0
- package/reference/schema/built-in-codecs/bson.md +480 -0
- package/reference/schema/built-in-codecs/csv.md +564 -0
- package/reference/schema/built-in-codecs/index.md +77 -0
- package/reference/schema/built-in-codecs/json/index.md +295 -0
- package/reference/schema/built-in-codecs/json/json-config.md +217 -0
- package/reference/{json-patch.md → schema/built-in-codecs/json/json-patch.md} +5 -5
- package/reference/{json-schema.md → schema/built-in-codecs/json/json-schema.md} +14 -47
- package/reference/schema/built-in-codecs/json/json-selection.md +322 -0
- package/reference/{json.md → schema/built-in-codecs/json/json.md} +32 -64
- package/reference/schema/built-in-codecs/messagepack.md +508 -0
- package/reference/schema/built-in-codecs/thrift.md +433 -0
- package/reference/schema/built-in-codecs/toon.md +1078 -0
- package/reference/{xml.md → schema/built-in-codecs/xml.md} +13 -9
- package/reference/schema/built-in-codecs/yaml.md +552 -0
- package/reference/{codec.md → schema/codec.md} +10 -10
- package/reference/{dynamic-optic.md → schema/dynamic-optic.md} +151 -5
- package/reference/{dynamic-schema.md → schema/dynamic-schema.md} +8 -8
- package/reference/schema/format.md +92 -0
- package/reference/schema/index.md +50 -0
- package/reference/schema/migration.md +297 -0
- package/reference/{modifier.md → schema/modifier.md} +58 -7
- package/reference/{optics.md → schema/optics.md} +2 -2
- package/reference/{patch.md → schema/patch.md} +1 -1
- package/{path-interpolator.md → reference/schema/path-interpolator.md} +165 -72
- package/reference/{schema-evolution → schema/schema-evolution}/as.md +8 -8
- package/reference/{schema-evolution → schema/schema-evolution}/index.md +2 -2
- package/reference/{schema-evolution → schema/schema-evolution}/into.md +8 -8
- package/reference/{schema-expr.md → schema/schema-expr.md} +110 -175
- package/reference/{schema.md → schema/schema.md} +12 -0
- package/reference/{structural-types.md → schema/structural-types.md} +1 -1
- package/reference/{type-class-derivation.md → schema/type-class-derivation.md} +63 -1
- package/reference/smithy.md +533 -0
- package/reference/sql/db-codec-deriver.md +71 -0
- package/reference/sql/db-codec.md +687 -0
- package/reference/sql/db-con.md +271 -0
- package/reference/sql/db-connection.md +153 -0
- package/reference/sql/db-param-writer.md +77 -0
- package/reference/sql/db-param.md +66 -0
- package/reference/sql/db-result-reader.md +146 -0
- package/reference/sql/db-tx.md +82 -0
- package/reference/sql/db-value.md +41 -0
- package/reference/sql/ddl.md +85 -0
- package/reference/sql/frag.md +254 -0
- package/reference/sql/index.md +341 -0
- package/reference/sql/repo.md +600 -0
- package/reference/sql/sql-dialect.md +73 -0
- package/reference/sql/sql-logger.md +62 -0
- package/reference/sql/sql-name-mapper.md +70 -0
- package/reference/sql/table-metadata.md +134 -0
- package/reference/sql/table.md +448 -0
- package/reference/sql/transactor-zio.md +399 -0
- package/reference/sql/transactor.md +353 -0
- package/reference/sql-zio.md +112 -0
- package/reference/streams/concurrent-operators.md +106 -0
- package/reference/streams/index.md +653 -0
- package/reference/streams/pipeline.md +718 -0
- package/reference/streams/reader.md +1284 -0
- package/reference/streams/scala-2-compatibility.md +55 -0
- package/reference/streams/sink.md +1426 -0
- package/reference/streams/stream.md +2526 -0
- package/reference/streams/writer.md +1045 -0
- package/reference/streams/zero-boxing.md +275 -0
- package/reference/telemetry.md +693 -0
- package/reference/typeid.md +5 -19
- package/sidebars.js +238 -43
- package/reference/formats.md +0 -694
- package/reference/http-model.md +0 -1716
- package/reference/streams.md +0 -989
- package/ringbuffer.md +0 -249
- /package/reference/{json-differ.md → schema/built-in-codecs/json/json-differ.md} +0 -0
- /package/reference/{dynamic-value.md → schema/dynamic-value.md} +0 -0
- /package/reference/{lazy.md → schema/lazy.md} +0 -0
- /package/reference/{reflect.md → schema/reflect.md} +0 -0
- /package/reference/{registers.md → schema/registers.md} +0 -0
- /package/reference/{schema-error.md → schema/schema-error.md} +0 -0
- /package/reference/{syntax.md → schema/syntax.md} +0 -0
- /package/reference/{validation.md → schema/validation.md} +0 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: scala-emitter
|
|
3
|
+
title: "ScalaEmitter"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`ScalaEmitter` is the core emission engine that converts IR models to formatted Scala source code. It provides the main entry point and methods to emit any IR construct as a properly formatted string.
|
|
7
|
+
|
|
8
|
+
## Use Cases
|
|
9
|
+
|
|
10
|
+
- Converting a complete `ScalaFile` IR to a Scala source string
|
|
11
|
+
- Emitting individual type definitions as Scala code
|
|
12
|
+
- Generating imports, annotations, methods, and type references
|
|
13
|
+
- Formatting code with consistent indentation and style
|
|
14
|
+
|
|
15
|
+
## Main Emission Method
|
|
16
|
+
|
|
17
|
+
Emit a complete Scala file:
|
|
18
|
+
|
|
19
|
+
```scala
|
|
20
|
+
import zio.blocks.codegen.ir._
|
|
21
|
+
import zio.blocks.codegen.emit._
|
|
22
|
+
|
|
23
|
+
val file = ScalaFile(
|
|
24
|
+
packageDecl = PackageDecl("com.example"),
|
|
25
|
+
types = List(
|
|
26
|
+
CaseClass("User", List(Field("id", TypeRef.Long)))
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
val config = EmitterConfig()
|
|
31
|
+
val sourceCode = ScalaEmitter.emit(file, config)
|
|
32
|
+
// sourceCode is a String ready to write to a .scala file
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Key Operations
|
|
36
|
+
|
|
37
|
+
All core operations are shown below:
|
|
38
|
+
|
|
39
|
+
### Emitting Type References
|
|
40
|
+
|
|
41
|
+
Convert a type reference to Scala syntax:
|
|
42
|
+
|
|
43
|
+
```scala
|
|
44
|
+
import zio.blocks.codegen.ir._
|
|
45
|
+
import zio.blocks.codegen.emit._
|
|
46
|
+
|
|
47
|
+
// These methods are used internally by emit, but available if you need them:
|
|
48
|
+
ScalaEmitter.emitTypeRef(TypeRef.String)
|
|
49
|
+
// Returns: "String"
|
|
50
|
+
|
|
51
|
+
ScalaEmitter.emitTypeRef(TypeRef.list(TypeRef.Int))
|
|
52
|
+
// Returns: "List[Int]"
|
|
53
|
+
|
|
54
|
+
ScalaEmitter.emitTypeRef(TypeRef.map(TypeRef.String, TypeRef.Int))
|
|
55
|
+
// Returns: "Map[String, Int]"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Emitting Type Parameters
|
|
59
|
+
|
|
60
|
+
Emit generic type parameters with bounds:
|
|
61
|
+
|
|
62
|
+
```scala
|
|
63
|
+
import zio.blocks.codegen.ir._
|
|
64
|
+
|
|
65
|
+
val unbounded = TypeParam("T")
|
|
66
|
+
// Emits: "T"
|
|
67
|
+
|
|
68
|
+
val bounded = TypeParam("T", upperBound = Some(TypeRef("Serializable")))
|
|
69
|
+
// Emits: "T <: Serializable"
|
|
70
|
+
|
|
71
|
+
val covariant = TypeParam("T", variance = Variance.Covariant)
|
|
72
|
+
// Emits: "+T"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Emitting Annotations
|
|
76
|
+
|
|
77
|
+
Convert annotations to Scala syntax:
|
|
78
|
+
|
|
79
|
+
```scala
|
|
80
|
+
import zio.blocks.codegen.ir._
|
|
81
|
+
|
|
82
|
+
val deprecated = Annotation("deprecated")
|
|
83
|
+
// Emits: "@deprecated"
|
|
84
|
+
|
|
85
|
+
val withArg = Annotation("Deprecated", args = List("message" -> "\"Use newMethod instead\""))
|
|
86
|
+
// Emits: "@Deprecated(message = \"Use newMethod instead\")"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Configuration
|
|
90
|
+
|
|
91
|
+
The emitter respects `EmitterConfig` settings:
|
|
92
|
+
|
|
93
|
+
```scala
|
|
94
|
+
import zio.blocks.codegen.ir._
|
|
95
|
+
import zio.blocks.codegen.emit._
|
|
96
|
+
|
|
97
|
+
val file = ScalaFile(PackageDecl("com.example"))
|
|
98
|
+
|
|
99
|
+
val config = EmitterConfig(
|
|
100
|
+
indentWidth = 2, // Spaces per indent level
|
|
101
|
+
sortImports = true, // Sort import statements
|
|
102
|
+
trailingCommas = true, // Add trailing commas in collections
|
|
103
|
+
scala3Syntax = true // Scala 3 syntax features
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
ScalaEmitter.emit(file, config)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
See [EmitterConfig](./emitter-config.md) for all available options.
|
|
110
|
+
|
|
111
|
+
## Examples
|
|
112
|
+
|
|
113
|
+
Practical examples demonstrate common usage:
|
|
114
|
+
|
|
115
|
+
### Example 1: Emit a Complete File
|
|
116
|
+
|
|
117
|
+
Generate a Scala file with multiple types:
|
|
118
|
+
|
|
119
|
+
```scala
|
|
120
|
+
import zio.blocks.codegen.ir._
|
|
121
|
+
import zio.blocks.codegen.emit._
|
|
122
|
+
|
|
123
|
+
val file = ScalaFile(
|
|
124
|
+
packageDecl = PackageDecl("com.api"),
|
|
125
|
+
imports = List(
|
|
126
|
+
Import.WildcardImport("zio"),
|
|
127
|
+
Import.SingleImport("scala.collection", "Seq")
|
|
128
|
+
),
|
|
129
|
+
types = List(
|
|
130
|
+
CaseClass(
|
|
131
|
+
"ApiResponse",
|
|
132
|
+
List(
|
|
133
|
+
Field("status", TypeRef.Int),
|
|
134
|
+
Field("data", TypeRef.optional(TypeRef.String))
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
val config = EmitterConfig(indentWidth = 2)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Emits:
|
|
144
|
+
|
|
145
|
+
```scala
|
|
146
|
+
import zio.blocks.codegen.emit._
|
|
147
|
+
ScalaEmitter.emit(file, config)
|
|
148
|
+
// res6: String = """package com.api
|
|
149
|
+
//
|
|
150
|
+
// import scala.collection.Seq
|
|
151
|
+
// import zio.*
|
|
152
|
+
//
|
|
153
|
+
// case class ApiResponse(
|
|
154
|
+
// status: Int,
|
|
155
|
+
// data: Option[String],
|
|
156
|
+
// )
|
|
157
|
+
// """
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Example 2: Cross-Scala Compatibility
|
|
161
|
+
|
|
162
|
+
Generate code for different Scala versions:
|
|
163
|
+
|
|
164
|
+
```scala
|
|
165
|
+
import zio.blocks.codegen.ir._
|
|
166
|
+
import zio.blocks.codegen.emit._
|
|
167
|
+
|
|
168
|
+
val file = ScalaFile(
|
|
169
|
+
packageDecl = PackageDecl("com.example"),
|
|
170
|
+
types = List(
|
|
171
|
+
Enum(
|
|
172
|
+
name = "Status",
|
|
173
|
+
cases = List(
|
|
174
|
+
EnumCase.SimpleCase("Active"),
|
|
175
|
+
EnumCase.SimpleCase("Inactive")
|
|
176
|
+
)
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
// For Scala 3: emits actual enum
|
|
182
|
+
val scala3Config = EmitterConfig(
|
|
183
|
+
scala3Syntax = true
|
|
184
|
+
)
|
|
185
|
+
val scala3Code = ScalaEmitter.emit(file, scala3Config)
|
|
186
|
+
|
|
187
|
+
// For Scala 2: emits sealed trait (fallback)
|
|
188
|
+
val scala2Config = EmitterConfig(
|
|
189
|
+
scala3Syntax = false
|
|
190
|
+
)
|
|
191
|
+
val scala2Code = ScalaEmitter.emit(file, scala2Config)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Scala 3 emits:
|
|
195
|
+
|
|
196
|
+
```scala
|
|
197
|
+
import zio.blocks.codegen.emit._
|
|
198
|
+
scala3Code
|
|
199
|
+
// res8: String = """package com.example
|
|
200
|
+
//
|
|
201
|
+
// enum Status {
|
|
202
|
+
// case Active, Inactive
|
|
203
|
+
// }
|
|
204
|
+
// """
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Scala 2 emits:
|
|
208
|
+
|
|
209
|
+
```scala
|
|
210
|
+
import zio.blocks.codegen.emit._
|
|
211
|
+
scala2Code
|
|
212
|
+
// res9: String = """package com.example
|
|
213
|
+
//
|
|
214
|
+
// sealed trait Status
|
|
215
|
+
//
|
|
216
|
+
// object Status {
|
|
217
|
+
// case object Active extends Status
|
|
218
|
+
// case object Inactive extends Status
|
|
219
|
+
// }
|
|
220
|
+
// """
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Example 3: Sealed Trait with Multiple Cases
|
|
224
|
+
|
|
225
|
+
Emit a complete ADT:
|
|
226
|
+
|
|
227
|
+
```scala
|
|
228
|
+
import zio.blocks.codegen.ir._
|
|
229
|
+
import zio.blocks.codegen.emit._
|
|
230
|
+
|
|
231
|
+
val file = ScalaFile(
|
|
232
|
+
packageDecl = PackageDecl("com.errors"),
|
|
233
|
+
types = List(
|
|
234
|
+
SealedTrait(
|
|
235
|
+
name = "DomainError",
|
|
236
|
+
cases = List(
|
|
237
|
+
SealedTraitCase.CaseClassCase(
|
|
238
|
+
CaseClass("ValidationError", List(
|
|
239
|
+
Field("field", TypeRef.String),
|
|
240
|
+
Field("message", TypeRef.String)
|
|
241
|
+
))
|
|
242
|
+
),
|
|
243
|
+
SealedTraitCase.CaseClassCase(
|
|
244
|
+
CaseClass("NotFound", List(
|
|
245
|
+
Field("resource", TypeRef.String),
|
|
246
|
+
Field("id", TypeRef.Long)
|
|
247
|
+
))
|
|
248
|
+
),
|
|
249
|
+
SealedTraitCase.CaseObjectCase("Unauthorized"),
|
|
250
|
+
SealedTraitCase.CaseObjectCase("InternalError")
|
|
251
|
+
)
|
|
252
|
+
)
|
|
253
|
+
)
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
val config = EmitterConfig(trailingCommas = true)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Emits:
|
|
260
|
+
|
|
261
|
+
```scala
|
|
262
|
+
import zio.blocks.codegen.emit._
|
|
263
|
+
ScalaEmitter.emit(file, config)
|
|
264
|
+
// res11: String = """package com.errors
|
|
265
|
+
//
|
|
266
|
+
// sealed trait DomainError
|
|
267
|
+
//
|
|
268
|
+
// object DomainError {
|
|
269
|
+
// case class ValidationError(
|
|
270
|
+
// field: String,
|
|
271
|
+
// message: String,
|
|
272
|
+
// ) extends DomainError
|
|
273
|
+
// case class NotFound(
|
|
274
|
+
// resource: String,
|
|
275
|
+
// id: Long,
|
|
276
|
+
// ) extends DomainError
|
|
277
|
+
// case object Unauthorized extends DomainError
|
|
278
|
+
// case object InternalError extends DomainError
|
|
279
|
+
// }
|
|
280
|
+
// """
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Example 4: Generic Types
|
|
284
|
+
|
|
285
|
+
Emit polymorphic types with proper type parameter syntax:
|
|
286
|
+
|
|
287
|
+
```scala
|
|
288
|
+
import zio.blocks.codegen.ir._
|
|
289
|
+
import zio.blocks.codegen.emit._
|
|
290
|
+
|
|
291
|
+
val file = ScalaFile(
|
|
292
|
+
packageDecl = PackageDecl("com.containers"),
|
|
293
|
+
types = List(
|
|
294
|
+
CaseClass(
|
|
295
|
+
name = "Wrapper",
|
|
296
|
+
fields = List(Field("value", TypeRef("A"))),
|
|
297
|
+
typeParams = List(
|
|
298
|
+
TypeParam("A")
|
|
299
|
+
)
|
|
300
|
+
),
|
|
301
|
+
CaseClass(
|
|
302
|
+
name = "Pair",
|
|
303
|
+
fields = List(
|
|
304
|
+
Field("left", TypeRef("A")),
|
|
305
|
+
Field("right", TypeRef("B"))
|
|
306
|
+
),
|
|
307
|
+
typeParams = List(
|
|
308
|
+
TypeParam("A"),
|
|
309
|
+
TypeParam("B")
|
|
310
|
+
)
|
|
311
|
+
)
|
|
312
|
+
)
|
|
313
|
+
)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Emits:
|
|
317
|
+
|
|
318
|
+
```scala
|
|
319
|
+
import zio.blocks.codegen.emit._
|
|
320
|
+
ScalaEmitter.emit(file, EmitterConfig())
|
|
321
|
+
// res13: String = """package com.containers
|
|
322
|
+
//
|
|
323
|
+
// case class Wrapper[A](
|
|
324
|
+
// value: A,
|
|
325
|
+
// )
|
|
326
|
+
//
|
|
327
|
+
// case class Pair[A, B](
|
|
328
|
+
// left: A,
|
|
329
|
+
// right: B,
|
|
330
|
+
// )
|
|
331
|
+
// """
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Example 5: Formatting Customization
|
|
335
|
+
|
|
336
|
+
Control code style with configuration:
|
|
337
|
+
|
|
338
|
+
```scala
|
|
339
|
+
import zio.blocks.codegen.ir._
|
|
340
|
+
import zio.blocks.codegen.emit._
|
|
341
|
+
|
|
342
|
+
val file = ScalaFile(
|
|
343
|
+
packageDecl = PackageDecl("com.example"),
|
|
344
|
+
imports = List(
|
|
345
|
+
Import.WildcardImport("scala.collection"),
|
|
346
|
+
Import.SingleImport("java.time", "Instant")
|
|
347
|
+
),
|
|
348
|
+
types = List(
|
|
349
|
+
CaseClass(
|
|
350
|
+
name = "Record",
|
|
351
|
+
fields = List(
|
|
352
|
+
Field("a", TypeRef.String),
|
|
353
|
+
Field("b", TypeRef.Int),
|
|
354
|
+
Field("c", TypeRef.Boolean)
|
|
355
|
+
)
|
|
356
|
+
)
|
|
357
|
+
)
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
// Wide indentation, sorted imports, trailing commas
|
|
361
|
+
val config = EmitterConfig(
|
|
362
|
+
indentWidth = 4,
|
|
363
|
+
sortImports = true,
|
|
364
|
+
trailingCommas = true
|
|
365
|
+
)
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Emits:
|
|
369
|
+
|
|
370
|
+
```scala
|
|
371
|
+
import zio.blocks.codegen.emit._
|
|
372
|
+
ScalaEmitter.emit(file, config)
|
|
373
|
+
// res15: String = """package com.example
|
|
374
|
+
//
|
|
375
|
+
// import java.time.Instant
|
|
376
|
+
// import scala.collection.*
|
|
377
|
+
//
|
|
378
|
+
// case class Record(
|
|
379
|
+
// a: String,
|
|
380
|
+
// b: Int,
|
|
381
|
+
// c: Boolean,
|
|
382
|
+
// )
|
|
383
|
+
// """
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## Design Philosophy
|
|
387
|
+
|
|
388
|
+
`ScalaEmitter` follows three principles:
|
|
389
|
+
|
|
390
|
+
1. **Pure**: No side effects. Takes IR + config, returns a string. Your code writes files.
|
|
391
|
+
2. **Configurable**: `EmitterConfig` controls formatting. Add options as needed for your generator.
|
|
392
|
+
3. **Cross-Scala**: Targets both Scala 3 (enums, derives, `*` imports) and Scala 2 (sealed traits, `_` imports) from the same IR.
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: scala-file
|
|
3
|
+
title: "ScalaFile"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`ScalaFile` is the root IR node representing a complete Scala source file. It holds everything needed to emit a compilable file: the package declaration, imports, and type definitions.
|
|
7
|
+
|
|
8
|
+
## Use Cases
|
|
9
|
+
|
|
10
|
+
- As the entry point to `ScalaEmitter.emit(file, config)` to generate source code
|
|
11
|
+
- As a container when building complex file structures with multiple types
|
|
12
|
+
- As the canonical representation of "what I want to emit as Scala"
|
|
13
|
+
|
|
14
|
+
## Construction
|
|
15
|
+
|
|
16
|
+
Build a `ScalaFile` with a package declaration, optional imports, and optional types:
|
|
17
|
+
|
|
18
|
+
```scala
|
|
19
|
+
import zio.blocks.codegen.ir._
|
|
20
|
+
|
|
21
|
+
val simpleFile = ScalaFile(
|
|
22
|
+
packageDecl = PackageDecl("com.example")
|
|
23
|
+
)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
With imports and types:
|
|
27
|
+
|
|
28
|
+
```scala
|
|
29
|
+
import zio.blocks.codegen.ir._
|
|
30
|
+
|
|
31
|
+
val file = ScalaFile(
|
|
32
|
+
packageDecl = PackageDecl("com.example"),
|
|
33
|
+
imports = List(
|
|
34
|
+
Import.WildcardImport("zio")
|
|
35
|
+
),
|
|
36
|
+
types = List(
|
|
37
|
+
CaseClass(
|
|
38
|
+
name = "User",
|
|
39
|
+
fields = List(Field("id", TypeRef.Long))
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Key Operations
|
|
46
|
+
|
|
47
|
+
All core operations are shown below:
|
|
48
|
+
|
|
49
|
+
### Accessing Components
|
|
50
|
+
|
|
51
|
+
Extract the parts of a `ScalaFile`:
|
|
52
|
+
|
|
53
|
+
```scala
|
|
54
|
+
import zio.blocks.codegen.emit._
|
|
55
|
+
// Read-only access to all components
|
|
56
|
+
file.packageDecl // PackageDecl
|
|
57
|
+
// res1: PackageDecl = PackageDecl("com.example")
|
|
58
|
+
file.imports // List[Import]
|
|
59
|
+
// res2: List[Import] = List(WildcardImport("zio"))
|
|
60
|
+
file.types // List[TypeDefinition]
|
|
61
|
+
// res3: List[TypeDefinition] = List(
|
|
62
|
+
// CaseClass(
|
|
63
|
+
// name = "User",
|
|
64
|
+
// fields = List(
|
|
65
|
+
// Field(
|
|
66
|
+
// name = "id",
|
|
67
|
+
// typeRef = TypeRef(name = "Long", typeArgs = List()),
|
|
68
|
+
// defaultValue = None,
|
|
69
|
+
// annotations = List(),
|
|
70
|
+
// doc = None
|
|
71
|
+
// )
|
|
72
|
+
// ),
|
|
73
|
+
// typeParams = List(),
|
|
74
|
+
// extendsTypes = List(),
|
|
75
|
+
// derives = List(),
|
|
76
|
+
// annotations = List(),
|
|
77
|
+
// companion = None,
|
|
78
|
+
// doc = None,
|
|
79
|
+
// isValueClass = false
|
|
80
|
+
// )
|
|
81
|
+
// )
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Building with Copy
|
|
85
|
+
|
|
86
|
+
Modify a file by copying with new values:
|
|
87
|
+
|
|
88
|
+
```scala
|
|
89
|
+
import zio.blocks.codegen.emit._
|
|
90
|
+
val updatedFile = file.copy(
|
|
91
|
+
types = file.types :+ CaseClass(
|
|
92
|
+
name = "Product",
|
|
93
|
+
fields = List(Field("name", TypeRef.String))
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
// updatedFile: ScalaFile = ScalaFile(
|
|
97
|
+
// packageDecl = PackageDecl("com.example"),
|
|
98
|
+
// imports = List(WildcardImport("zio")),
|
|
99
|
+
// types = List(
|
|
100
|
+
// CaseClass(
|
|
101
|
+
// name = "User",
|
|
102
|
+
// fields = List(
|
|
103
|
+
// Field(
|
|
104
|
+
// name = "id",
|
|
105
|
+
// typeRef = TypeRef(name = "Long", typeArgs = List()),
|
|
106
|
+
// defaultValue = None,
|
|
107
|
+
// annotations = List(),
|
|
108
|
+
// doc = None
|
|
109
|
+
// )
|
|
110
|
+
// ),
|
|
111
|
+
// typeParams = List(),
|
|
112
|
+
// extendsTypes = List(),
|
|
113
|
+
// derives = List(),
|
|
114
|
+
// annotations = List(),
|
|
115
|
+
// companion = None,
|
|
116
|
+
// doc = None,
|
|
117
|
+
// isValueClass = false
|
|
118
|
+
// ),
|
|
119
|
+
// CaseClass(
|
|
120
|
+
// name = "Product",
|
|
121
|
+
// fields = List(
|
|
122
|
+
// Field(
|
|
123
|
+
// name = "name",
|
|
124
|
+
// typeRef = TypeRef(name = "String", typeArgs = List()),
|
|
125
|
+
// defaultValue = None,
|
|
126
|
+
// annotations = List(),
|
|
127
|
+
// doc = None
|
|
128
|
+
// )
|
|
129
|
+
// ),
|
|
130
|
+
// typeParams = List(),
|
|
131
|
+
// extendsTypes = List(),
|
|
132
|
+
// derives = List(),
|
|
133
|
+
// annotations = List(),
|
|
134
|
+
// companion = None,
|
|
135
|
+
// doc = None,
|
|
136
|
+
// isValueClass = false
|
|
137
|
+
// )
|
|
138
|
+
// )
|
|
139
|
+
// )
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Emitting to Source
|
|
143
|
+
|
|
144
|
+
Generate Scala source from the file:
|
|
145
|
+
|
|
146
|
+
```scala
|
|
147
|
+
import zio.blocks.codegen.emit._
|
|
148
|
+
|
|
149
|
+
val config = EmitterConfig()
|
|
150
|
+
val sourceCode = ScalaEmitter.emit(file, config)
|
|
151
|
+
// sourceCode is a String ready to write to a .scala file
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Examples
|
|
155
|
+
|
|
156
|
+
Practical examples demonstrate common usage. Each builds a `ScalaFile`, calls `ScalaEmitter.emit()`, and displays the resulting output:
|
|
157
|
+
|
|
158
|
+
### Example 1: Minimal File
|
|
159
|
+
|
|
160
|
+
A file with just a package and one case class (all examples use `zio.blocks.codegen.ir._` and `zio.blocks.codegen.emit._` imports):
|
|
161
|
+
|
|
162
|
+
```scala
|
|
163
|
+
import zio.blocks.codegen.ir._
|
|
164
|
+
import zio.blocks.codegen.emit._
|
|
165
|
+
|
|
166
|
+
val minimal = ScalaFile(
|
|
167
|
+
packageDecl = PackageDecl("com.example"),
|
|
168
|
+
types = List(
|
|
169
|
+
CaseClass(
|
|
170
|
+
name = "Empty",
|
|
171
|
+
fields = Nil
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Emits:
|
|
178
|
+
|
|
179
|
+
```scala
|
|
180
|
+
import zio.blocks.codegen.emit._
|
|
181
|
+
ScalaEmitter.emit(minimal, EmitterConfig())
|
|
182
|
+
// res6: String = """package com.example
|
|
183
|
+
//
|
|
184
|
+
// case class Empty()
|
|
185
|
+
// """
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Example 2: File with Multiple Types
|
|
189
|
+
|
|
190
|
+
A file with a sealed trait and case classes:
|
|
191
|
+
|
|
192
|
+
```scala
|
|
193
|
+
import zio.blocks.codegen.ir._
|
|
194
|
+
import zio.blocks.codegen.emit._
|
|
195
|
+
|
|
196
|
+
val multiType = ScalaFile(
|
|
197
|
+
packageDecl = PackageDecl("com.payment"),
|
|
198
|
+
imports = List(Import.WildcardImport("zio")),
|
|
199
|
+
types = List(
|
|
200
|
+
SealedTrait(
|
|
201
|
+
name = "PaymentMethod",
|
|
202
|
+
cases = List(
|
|
203
|
+
SealedTraitCase.CaseClassCase(
|
|
204
|
+
CaseClass(
|
|
205
|
+
"Card",
|
|
206
|
+
List(Field("cardNumber", TypeRef.String))
|
|
207
|
+
)
|
|
208
|
+
),
|
|
209
|
+
SealedTraitCase.CaseObjectCase("Cash")
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Emits:
|
|
217
|
+
|
|
218
|
+
```scala
|
|
219
|
+
import zio.blocks.codegen.emit._
|
|
220
|
+
ScalaEmitter.emit(multiType, EmitterConfig())
|
|
221
|
+
// res8: String = """package com.payment
|
|
222
|
+
//
|
|
223
|
+
// import zio.*
|
|
224
|
+
//
|
|
225
|
+
// sealed trait PaymentMethod
|
|
226
|
+
//
|
|
227
|
+
// object PaymentMethod {
|
|
228
|
+
// case class Card(
|
|
229
|
+
// cardNumber: String,
|
|
230
|
+
// ) extends PaymentMethod
|
|
231
|
+
// case object Cash extends PaymentMethod
|
|
232
|
+
// }
|
|
233
|
+
// """
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Example 3: File with Imports and Type Parameters
|
|
237
|
+
|
|
238
|
+
A file demonstrating generic types and selective imports:
|
|
239
|
+
|
|
240
|
+
```scala
|
|
241
|
+
import zio.blocks.codegen.ir._
|
|
242
|
+
import zio.blocks.codegen.emit._
|
|
243
|
+
|
|
244
|
+
val generic = ScalaFile(
|
|
245
|
+
packageDecl = PackageDecl("com.containers"),
|
|
246
|
+
imports = List(
|
|
247
|
+
Import.SingleImport("scala.collection", "Seq"),
|
|
248
|
+
Import.WildcardImport("zio")
|
|
249
|
+
),
|
|
250
|
+
types = List(
|
|
251
|
+
CaseClass(
|
|
252
|
+
name = "Wrapper",
|
|
253
|
+
fields = List(
|
|
254
|
+
Field("items", TypeRef("Seq", List(TypeRef("T"))))
|
|
255
|
+
),
|
|
256
|
+
typeParams = List(TypeParam("T"))
|
|
257
|
+
)
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Emits:
|
|
263
|
+
|
|
264
|
+
```scala
|
|
265
|
+
import zio.blocks.codegen.emit._
|
|
266
|
+
ScalaEmitter.emit(generic, EmitterConfig())
|
|
267
|
+
// res10: String = """package com.containers
|
|
268
|
+
//
|
|
269
|
+
// import scala.collection.Seq
|
|
270
|
+
// import zio.*
|
|
271
|
+
//
|
|
272
|
+
// case class Wrapper[T](
|
|
273
|
+
// items: Seq[T],
|
|
274
|
+
// )
|
|
275
|
+
// """
|
|
276
|
+
```
|