@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,295 @@
1
+ ---
2
+ id: index
3
+ title: "JSON Codec"
4
+ ---
5
+
6
+ The JSON codec module provides complete, type-safe support for working with JSON data in ZIO Blocks. It includes an ADT for representing JSON values, a fluent navigation API (`JsonSelection`), configurable encoding/decoding (`JsonCodec` with `WriterConfig`/`ReaderConfig`), composable patches for transformations, a diff algorithm for computing minimal changes, and full JSON Schema 2020-12 support for validation and code generation.
7
+
8
+ **Core types:** `Json`, `JsonCodec`, `JsonSelection`, `JsonPatch`, `JsonDiffer`, `JsonSchema`, `JsonType`.
9
+
10
+ ```scala
11
+ import zio.blocks.schema._
12
+ import zio.blocks.schema.json._
13
+
14
+ // Represent any JSON value
15
+ val person = Json.Object("name" -> Json.String("Alice"), "age" -> Json.Number(30))
16
+
17
+ // Navigate with fluent API
18
+ val age = person.get("age") // JsonSelection
19
+
20
+ // Encode to string
21
+ val encoded = person.print(WriterConfig)
22
+
23
+ // Compute minimal patches
24
+ val updated = person.set(p".age", Json.Number(31))
25
+ val patch = JsonPatch.diff(person, updated)
26
+
27
+ // Validate against a schema
28
+ case class Person(name: String, age: Int)
29
+ object Person { implicit val schema: Schema[Person] = Schema.derived }
30
+ val schema: JsonSchema = Schema[Person].toJsonSchema
31
+ schema.conforms(person) // true
32
+ ```
33
+
34
+ ## Installation
35
+
36
+ The JSON codec is included in the ZIO Blocks Schema module. Add it to your `build.sbt`:
37
+
38
+ ```scala
39
+ libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.51"
40
+ ```
41
+
42
+ For Scala.js projects, use `%%%` instead:
43
+
44
+ ```scala
45
+ libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.51"
46
+ ```
47
+
48
+ **Supported Scala versions:** 2.13.x and 3.x
49
+
50
+ The JSON codec is fully integrated into ZIO Blocks Schema and provides complete type-safe JSON support with no external dependencies beyond core ZIO libraries.
51
+
52
+ ## How They Work Together
53
+
54
+ The JSON module workflow moves through representation, navigation, encoding/decoding, diffing, patching, and validation:
55
+
56
+ ```
57
+ Parse/Create JSON
58
+ ↓
59
+ Json (ADT: Object, Array, String, Number, Boolean, Null)
60
+ ├─ Navigate with JsonSelection (fluent query API)
61
+ ├─ Understand with JsonType (type information)
62
+ └─ Transform via JsonPatch (composable operations)
63
+ ↓
64
+ JsonCodec (encode/decode)
65
+ ├─ WriterConfig (indent, escaping, order)
66
+ ├─ ReaderConfig (strict validation, number handling)
67
+ └─ MergeStrategy (field conflict resolution)
68
+ ↓
69
+ JsonDiffer (diff algorithm)
70
+ └─ Produces JsonPatch (minimal changes)
71
+ ↓
72
+ JsonPatch.apply (transform JSON)
73
+ ↓
74
+ JsonSchema (validate or generate)
75
+ ├─ Derive from Scala types
76
+ ├─ Validate JSON conformance
77
+ └─ Generate documentation
78
+ ```
79
+
80
+ **Type Relationships:**
81
+ - `Json` is the central value type; all operations start with or produce it
82
+ - `JsonSelection` provides fluent navigation through nested `Json` structures
83
+ - `JsonCodec` bridges Scala types ↔ `Json` with configurable `WriterConfig` and `ReaderConfig`
84
+ - `JsonDiffer` computes `JsonPatch` by comparing two `Json` values
85
+ - `JsonPatch` transforms `Json` values with composable operations
86
+ - `JsonSchema` validates `Json` conformance and derives from Scala `Schema` types
87
+ - `JsonType` provides type information for `Json` values at runtime
88
+
89
+ ## Common Patterns
90
+
91
+ ### Pattern 1: Parse, Transform, Serialize
92
+
93
+ Read JSON, modify it, and write it back:
94
+
95
+ ```scala
96
+ import zio.blocks.schema._
97
+ import zio.blocks.schema.json.{Json, WriterConfig}
98
+
99
+ val jsonString = """{"name": "Alice", "age": 30}"""
100
+ val json = Json.parseUnsafe(jsonString)
101
+
102
+ // Transform
103
+ val updated = json.modify(p".age") {
104
+ case Json.Number(n) => Json.Number(n + 1)
105
+ case other => other
106
+ }
107
+
108
+ // Serialize
109
+ val output = updated.print(WriterConfig.withIndentionStep2)
110
+ ```
111
+
112
+ ### Pattern 2: Diff and Apply
113
+
114
+ Compute changes and apply them:
115
+
116
+ ```scala
117
+ import zio.blocks.schema.json.{Json, JsonPatch}
118
+
119
+ val original = Json.Object("count" -> Json.Number(0))
120
+ val target = Json.Object("count" -> Json.Number(1), "active" -> Json.Boolean(true))
121
+
122
+ // Compute the diff
123
+ val patch = JsonPatch.diff(original, target)
124
+
125
+ // Apply to reconstruct
126
+ val result = patch.apply(original)
127
+ // Right({"count": 1, "active": true})
128
+ ```
129
+
130
+ ### Pattern 3: Validate with Schema
131
+
132
+ Generate and validate using schemas:
133
+
134
+ ```scala
135
+ import zio.blocks.schema._
136
+ import zio.blocks.schema.json.{Json, JsonSchema}
137
+
138
+ case class User(name: String, email: String, age: Int)
139
+ object User {
140
+ implicit val schema: Schema[User] = Schema.derived
141
+ }
142
+
143
+ val jsonSchema: JsonSchema = Schema[User].toJsonSchema
144
+ val validJson = Json.Object(
145
+ "name" -> Json.String("Alice"),
146
+ "email" -> Json.String("alice@example.com"),
147
+ "age" -> Json.Number(30)
148
+ )
149
+
150
+ jsonSchema.conforms(validJson) // true
151
+ ```
152
+
153
+ ### Pattern 4: Navigate and Extract with JsonSelection
154
+
155
+ Use fluent API to navigate nested structures and extract values:
156
+
157
+ ```scala
158
+ import zio.blocks.schema._
159
+ import zio.blocks.schema.json.Json
160
+
161
+ val data = Json.Object(
162
+ "users" -> Json.Array(
163
+ Json.Object("name" -> Json.String("Alice"), "age" -> Json.Number(30)),
164
+ Json.Object("name" -> Json.String("Bob"), "age" -> Json.Number(25))
165
+ )
166
+ )
167
+
168
+ // Navigate to first user's age
169
+ val age: Either[SchemaError, Int] = data
170
+ .get("users") // JsonSelection
171
+ (0) // Navigate to first array element
172
+ .get("age") // Navigate to age field
173
+ .as[Int] // Decode to Int
174
+
175
+ // Check values
176
+ val ageValue = data.get("users")(0).get("age").one // Right(Json.Number(30))
177
+ ```
178
+
179
+ ### Pattern 5: Encode and Decode with Configuration
180
+
181
+ Control output formatting and parsing behavior:
182
+
183
+ ```scala
184
+ import zio.blocks.schema._
185
+ import zio.blocks.schema.json.{Json, WriterConfig}
186
+
187
+ case class Config(host: String, port: Int)
188
+ object Config {
189
+ implicit val schema: Schema[Config] = Schema.derived
190
+ }
191
+
192
+ val config = Config("localhost", 8080)
193
+ val json = config.toJson
194
+
195
+ // Encode with custom formatting
196
+ val pretty = json.print(WriterConfig.withIndentionStep(2))
197
+
198
+ // Decode: parse back to Json, then decode
199
+ val parsed: Json = Json.parseUnsafe(pretty)
200
+ val config2: Either[SchemaError, Config] = parsed.as[Config]
201
+ ```
202
+
203
+ ### Pattern 6: Compose Multiple Patches
204
+
205
+ Chain multiple transformations into a single patch:
206
+
207
+ ```scala
208
+ import zio.blocks.schema._
209
+ import zio.blocks.schema.json.{Json, JsonPatch}
210
+
211
+ val original = Json.Object("x" -> Json.Number(1), "y" -> Json.Number(2))
212
+
213
+ // Build patches independently
214
+ val patchX = JsonPatch.diff(
215
+ original,
216
+ original.set(p".x", Json.Number(10))
217
+ )
218
+
219
+ val patchY = JsonPatch.diff(
220
+ original.set(p".x", Json.Number(10)),
221
+ original.set(p".x", Json.Number(10)).set(p".y", Json.Number(20))
222
+ )
223
+
224
+ // Compose them
225
+ val combined = patchX ++ patchY
226
+ combined.apply(original)
227
+ // Right({"x": 10, "y": 20})
228
+ ```
229
+
230
+ ## Integration Points
231
+
232
+ **With other codecs:** `Json` values convert to/from other formats (Avro, TOON, etc.) via `DynamicValue`:
233
+
234
+ ```scala
235
+ import zio.blocks.schema.json.Json
236
+ import zio.blocks.schema.DynamicValue
237
+
238
+ val json = Json.parseUnsafe("""{"name": "Alice"}""")
239
+ val dynamic: DynamicValue = json.toDynamicValue
240
+
241
+ // Convert to other formats using DynamicValue
242
+ ```
243
+
244
+ **With Schema system:** `Schema` enables automatic JSON encoding/decoding:
245
+
246
+ ```scala
247
+ import zio.blocks.schema._
248
+ import zio.blocks.schema.json.Json
249
+
250
+ case class Person(name: String, age: Int)
251
+ object Person {
252
+ implicit val schema: Schema[Person] = Schema.derived
253
+ }
254
+
255
+ // Encode using Schema-based extension methods
256
+ val person = Person("Alice", 30)
257
+ val json = person.toJson
258
+ val jsonString = person.toJsonString
259
+
260
+ // Decode: parse and extract with Schema
261
+ val parsed: Json = Json.parseUnsafe(jsonString)
262
+ val decoded: Either[SchemaError, Person] = parsed.as[Person]
263
+ ```
264
+
265
+ **With patching system:** `JsonPatch` and `JsonDiffer` integrate with generic `Patch` infrastructure:
266
+
267
+ ```scala
268
+ import zio.blocks.schema.json.{Json, JsonPatch}
269
+ import zio.blocks.schema.patch.DynamicPatch
270
+
271
+ val jsonPatch: JsonPatch = JsonPatch.root(JsonPatch.Op.Set(Json.Null))
272
+ val dynamicPatch: DynamicPatch = jsonPatch.toDynamicPatch
273
+ ```
274
+
275
+ **With optics and navigation:** `JsonSelection` provides query-like access complementary to `Optic` system:
276
+
277
+ - `JsonSelection` — runtime navigation through unknown JSON structures
278
+ - `Optic` — compile-time, type-safe navigation through known Scala types
279
+ - Both support nested access, filtering, and composition
280
+
281
+ **With validation:** `JsonSchema` integrates with Schema `Validation` system:
282
+
283
+ - Derive `JsonSchema` from Scala `Schema[A]`
284
+ - Validate raw JSON before type-safe decoding
285
+ - Compose with logical operators (allOf, anyOf, oneOf)
286
+
287
+ ## Type Pages
288
+
289
+ - **[Json](./json.md)** — The core ADT representing JSON values with six cases (Object, Array, String, Number, Boolean, Null). Covers construction, navigation, modification, transformation, filtering, merging, and encoding.
290
+
291
+ - **[JsonPatch](./json-patch.md)** — Composable patches for transforming JSON values. Create patches via diff or manually, compose them with `++`, and apply with different failure modes (Strict, Lenient, Clobber).
292
+
293
+ - **[JsonDiffer](./json-differ.md)** — Diff algorithm computing minimal patches. Uses smart strategies per type: NumberDelta for numbers, LCS-based StringEdit for strings, ArrayEdit with insertion/deletion for arrays, and ObjectEdit for fields.
294
+
295
+ - **[JSON Schema](./json-schema.md)** — Full JSON Schema 2020-12 support for validation and code generation. Derive schemas from Scala types, validate JSON, construct schemas manually with builders, and combine with logical operators.
@@ -0,0 +1,217 @@
1
+ ---
2
+ id: json-config
3
+ title: "JSON Configuration"
4
+ ---
5
+
6
+ The JSON codec module provides four configuration types for controlling encoding and decoding behavior: `WriterConfig`, `ReaderConfig`, `MergeStrategy`, and `NameMapper`. These types allow fine-grained control over how JSON is serialized and deserialized.
7
+
8
+ ## WriterConfig
9
+
10
+ `WriterConfig` controls the formatting and content of encoded JSON output. Use it when calling `Json#print` on `Json` values or when encoding values with specific formatting requirements.
11
+
12
+ ### Configuration Options
13
+
14
+ | Option | Type | Default | Purpose |
15
+ |--------------------|---------|---------|---------------------------------------------------------------|
16
+ | `indentionStep` | Int | 0 | Spaces per indentation level (0 = compact JSON) |
17
+ | `escapeUnicode` | Boolean | false | Escape non-ASCII characters as `\uXXXX` for ASCII-only output |
18
+ | `preferredBufSize` | Int | 32768 | Internal buffer size in bytes for streaming |
19
+
20
+ ### Usage Examples
21
+
22
+ Pretty-print JSON output with configurable indentation:
23
+
24
+ ```scala
25
+ import zio.blocks.schema._
26
+ import zio.blocks.schema.json.{WriterConfig}
27
+
28
+ case class Config(server: String, port: Int, debug: Boolean)
29
+ object Config { implicit val schema: Schema[Config] = Schema.derived }
30
+
31
+ val config = Config("localhost", 8080, true)
32
+ val json = config.toJson
33
+
34
+ // Pretty-printed with 2-space indentation
35
+ val pretty = json.print(WriterConfig.withIndentionStep(2))
36
+ // {
37
+ // "server": "localhost",
38
+ // "port": 8080,
39
+ // "debug": true
40
+ // }
41
+ ```
42
+
43
+ Configure custom indentation for JSON output:
44
+
45
+ ```scala
46
+ import zio.blocks.schema._
47
+ import zio.blocks.schema.json.WriterConfig
48
+
49
+ case class User(name: String, email: String, age: Int)
50
+ object User { implicit val schema: Schema[User] = Schema.derived }
51
+
52
+ val user = User("Alice", "alice@example.com", 30)
53
+ val json = user.toJson
54
+
55
+ // 4-space indentation
56
+ val sorted = json.print(WriterConfig
57
+ .withIndentionStep(4)
58
+ )
59
+ // {
60
+ // "name": "Alice",
61
+ // "email": "alice@example.com",
62
+ // "age": 30
63
+ // }
64
+ ```
65
+
66
+ Escape non-ASCII characters for ASCII-only transmission:
67
+
68
+ ```scala
69
+ import zio.blocks.schema._
70
+ import zio.blocks.schema.json.WriterConfig
71
+
72
+ case class Message(text: String)
73
+ object Message { implicit val schema: Schema[Message] = Schema.derived }
74
+
75
+ val msg = Message("Hello 世界")
76
+ val json = msg.toJson
77
+
78
+ // Escape non-ASCII characters - non-ASCII become \uXXXX sequences
79
+ val ascii = json.print(WriterConfig.withEscapeUnicode(true))
80
+ // Output: {"text":"Hello \\u4e16\\u754c"}
81
+ ```
82
+
83
+ ## ReaderConfig
84
+
85
+ `ReaderConfig` controls how JSON input is parsed and validated during decoding. Use it when calling `Json.parse()` with custom parsing behavior.
86
+
87
+ ### Configuration Options
88
+
89
+ | Option | Type | Default | Purpose |
90
+ |------------------------|---------|---------|----------------------------------------|
91
+ | `checkForEndOfInput` | Boolean | true | Verify no extra input after valid JSON |
92
+ | `preferredCharBufSize` | Int | 8192 | Internal character buffer size |
93
+
94
+ ### Usage Examples
95
+
96
+ Allow trailing whitespace after valid JSON during parsing:
97
+
98
+ ```scala
99
+ import zio.blocks.schema._
100
+ import zio.blocks.schema.json.{Json, ReaderConfig}
101
+
102
+ // Lenient: allow trailing whitespace
103
+ val lenientConfig = ReaderConfig.withCheckForEndOfInput(false)
104
+
105
+ val jsonString = """{"name": "Alice"} """ // Trailing spaces
106
+ val result = Json.parse(jsonString, lenientConfig)
107
+ // Right(Json.Object(...))
108
+ ```
109
+
110
+ ## MergeStrategy
111
+
112
+ `MergeStrategy` determines how field conflicts are resolved when merging two JSON objects. It provides strategies for different use cases, from strict validation to lenient concatenation.
113
+
114
+ **Available Strategies:**
115
+ - `Strict` — Fails if the same field appears in both objects
116
+ - `Right` — The right object's values override the left's
117
+ - `Left` — The left object's values take precedence
118
+ - Additional strategies may be available depending on your use case
119
+
120
+ For details on merge strategies and their usage, see the Merging section of the [Json](./json.md) documentation.
121
+
122
+ ## NameMapper
123
+
124
+ `NameMapper` customizes how field names are transformed between Scala types and JSON representation. It enables patterns like camelCase ↔ snake_case conversion.
125
+
126
+ ### Built-in Mappers
127
+
128
+ Use identity mapping to keep field names unchanged:
129
+
130
+ ```scala
131
+ import zio.blocks.schema._
132
+
133
+ case class User(firstName: String, lastName: String)
134
+ object User {
135
+ implicit val schema: Schema[User] = Schema.derived
136
+ }
137
+
138
+ // Default: no transformation
139
+ val user = User("Alice", "Smith")
140
+ val json = user.toJson
141
+ // {"firstName": "Alice", "lastName": "Smith"}
142
+ ```
143
+
144
+ **Snake Case:**
145
+ Convert camelCase to snake_case:
146
+
147
+ ```scala
148
+ import zio.blocks.schema._
149
+
150
+ case class User(firstName: String, lastName: String)
151
+ object User {
152
+ implicit val schema: Schema[User] = Schema.derived
153
+ implicit val nameMapper: NameMapper = NameMapper.SnakeCase
154
+ }
155
+
156
+ val user = User("Alice", "Smith")
157
+ val json = user.toJson
158
+ // {"first_name": "Alice", "last_name": "Smith"}
159
+ ```
160
+
161
+ **Kebab Case:**
162
+ Convert camelCase to kebab-case:
163
+
164
+ ```scala
165
+ import zio.blocks.schema._
166
+
167
+ case class User(firstName: String, lastName: String)
168
+ object User {
169
+ implicit val schema: Schema[User] = Schema.derived
170
+ implicit val nameMapper: NameMapper = NameMapper.KebabCase
171
+ }
172
+
173
+ val user = User("Alice", "Smith")
174
+ val json = user.toJson
175
+ // {"first-name": "Alice", "last-name": "Smith"}
176
+ ```
177
+
178
+ **Custom Mappers:**
179
+ Additional custom name mappers may be available depending on your needs. The built-in mappers (Identity, SnakeCase, KebabCase) cover most common use cases.
180
+
181
+ ## Combining Configuration
182
+
183
+ Use multiple configuration options together for fine-grained control:
184
+
185
+ ```scala
186
+ import zio.blocks.schema._
187
+ import zio.blocks.schema.json.WriterConfig
188
+
189
+ case class Config(server: String, port: Int, timeout: Option[Int])
190
+ object Config { implicit val schema: Schema[Config] = Schema.derived }
191
+
192
+ val config = Config("example.com", 443, None)
193
+ val json = config.toJson
194
+
195
+ // Pretty-printed with 4-space indentation
196
+ val output = json.print(WriterConfig
197
+ .withIndentionStep(4)
198
+ )
199
+ // {
200
+ // "server": "example.com",
201
+ // "port": 443
202
+ // }
203
+ ```
204
+
205
+ ## Performance Implications
206
+
207
+ - **WriterConfig:** Indentation increases output size but has minimal performance impact
208
+ - **ReaderConfig:** `checkForEndOfInput` adds one comparison
209
+ - **MergeStrategy:** Strategy choice affects merge performance based on use case
210
+ - **NameMapper:** Applied once per field during schema derivation; zero runtime cost if identity mapping
211
+
212
+ ## Best Practices
213
+
214
+ 1. **Use WriterConfig for human-readable output only** — Compact output is faster for wire transmission
215
+ 2. **Choose MergeStrategy based on use case** — Strict for validation, others for defaults
216
+ 3. **Standardize on one NameMapper** across your codebase to avoid confusion
217
+ 4. **Cache WriterConfig/ReaderConfig instances** — They're immutable and can be reused
@@ -338,7 +338,7 @@ combinedPatch.apply(personJson)
338
338
 
339
339
  ### Converting
340
340
 
341
- `toDynamicPatch` converts a `JsonPatch` to a [`DynamicPatch`](./patch.md). This is always safe — every JSON operation maps to a corresponding dynamic operation. `NumberDelta` widens to `BigDecimalDelta`:
341
+ `toDynamicPatch` converts a `JsonPatch` to a `DynamicPatch`. This is always safe — every JSON operation maps to a corresponding dynamic operation. `NumberDelta` widens to `BigDecimalDelta`:
342
342
 
343
343
  ```scala
344
344
  case class JsonPatch(ops: Chunk[JsonPatch.JsonPatchOp]) {
@@ -386,7 +386,7 @@ modeJson.patch(modePatch, PatchMode.Strict)
386
386
  // SchemaError(
387
387
  // List(
388
388
  // ExpectationMismatch(
389
- // source = DynamicOptic(IndexedSeq()),
389
+ // source = DynamicOptic(ArraySeq()),
390
390
  // expectation = "Key 'a' already exists in object"
391
391
  // )
392
392
  // )
@@ -723,7 +723,7 @@ fieldPatch.apply(doc)
723
723
  // res40: Either[SchemaError, Json] = Left(
724
724
  // SchemaError(
725
725
  // List(
726
- // MissingField(source = DynamicOptic(IndexedSeq()), fieldName = "updatedAt")
726
+ // MissingField(source = DynamicOptic(ArraySeq()), fieldName = "updatedAt")
727
727
  // )
728
728
  // )
729
729
  // )
@@ -769,7 +769,7 @@ val dynPatch: DynamicPatch = jsonPatch.toDynamicPatch
769
769
  val back: Either[SchemaError, JsonPatch] = JsonPatch.fromDynamicPatch(dynPatch)
770
770
  ```
771
771
 
772
- See [Patching](./patch.md) for the typed `Patch[S]` API.
772
+ For the typed `Patch[S]` API, see the Patching documentation.
773
773
 
774
774
  ### Serialization
775
775
 
@@ -782,7 +782,7 @@ import zio.blocks.schema.Schema
782
782
  val schema: Schema[JsonPatch] = implicitly[Schema[JsonPatch]]
783
783
  ```
784
784
 
785
- See [Codec & Format](./codec.md) for how to derive and use codecs.
785
+ For codec derivation and usage details, see the Codec & Format documentation.
786
786
 
787
787
  ## Examples
788
788
 
@@ -27,9 +27,7 @@ Key features:
27
27
 
28
28
  ## Deriving JSON Schema from Schema
29
29
 
30
- The most common use case is deriving a JSON Schema from an existing `Schema[A]`.
31
-
32
- ### Basic Derivation
30
+ The most common use case is deriving a JSON Schema from an existing `Schema[A]`. You can derive directly from the schema or through a `JsonCodec` for more control.
33
31
 
34
32
  ```scala
35
33
  import zio.blocks.schema._
@@ -40,9 +38,13 @@ object Person {
40
38
  implicit val schema: Schema[Person] = Schema.derived
41
39
  }
42
40
 
43
- // Get JSON Schema directly from Schema
41
+ // Direct derivation
44
42
  val jsonSchema: JsonSchema = Schema[Person].toJsonSchema
45
43
 
44
+ // Or derive through JsonCodec for more control
45
+ val codec = Schema[Person].derive(JsonFormat)
46
+ val jsonSchema2 = codec.toJsonSchema
47
+
46
48
  // The derived schema validates JSON values
47
49
  val valid = Json.Object("name" -> Json.String("Alice"), "age" -> Json.Number(30))
48
50
  val invalid = Json.Object("name" -> Json.Number(123))
@@ -51,24 +53,6 @@ jsonSchema.conforms(valid) // true
51
53
  jsonSchema.conforms(invalid) // false
52
54
  ```
53
55
 
54
- ### Through JsonCodec
55
-
56
- For more control, derive through `JsonCodec`:
57
-
58
- ```scala
59
- import zio.blocks.schema._
60
- import zio.blocks.schema.json._
61
-
62
- case class User(email: String, active: Boolean)
63
- object User {
64
- implicit val schema: Schema[User] = Schema.derived
65
- }
66
-
67
- // Derive codec first, then get JSON Schema
68
- val codec = Schema[User].derive(JsonFormat)
69
- val jsonSchema = codec.toJsonSchema
70
- ```
71
-
72
56
  ## Creating Schemas
73
57
 
74
58
  ### Boolean Schemas
@@ -197,22 +181,14 @@ Create schemas for object validation:
197
181
  import zio.blocks.schema.json.{JsonSchema, JsonSchemaType}
198
182
  import zio.blocks.chunk.ChunkMap
199
183
 
200
- // Object with properties
184
+ // Object with properties and constraints
201
185
  val person = JsonSchema.obj(
202
- properties = Some(ChunkMap(
203
- "name" -> JsonSchema.ofType(JsonSchemaType.String),
204
- "age" -> JsonSchema.ofType(JsonSchemaType.Integer)
205
- )),
206
- required = Some(Set("name"))
207
- )
208
-
209
- // Object with no additional properties
210
- val strictPerson = JsonSchema.obj(
211
186
  properties = Some(ChunkMap(
212
187
  "name" -> JsonSchema.ofType(JsonSchemaType.String),
213
188
  "age" -> JsonSchema.ofType(JsonSchemaType.Integer)
214
189
  )),
215
190
  required = Some(Set("name")),
191
+ // Reject properties not defined above
216
192
  additionalProperties = Some(JsonSchema.False)
217
193
  )
218
194
  ```
@@ -320,7 +296,7 @@ val paymentSchema = JsonSchema.Object(
320
296
  ### Basic Validation
321
297
 
322
298
  ```scala
323
- import zio.blocks.schema.json.{JsonSchema, Json, JsonSchemaType}
299
+ import zio.blocks.schema.json.{JsonSchema, Json, JsonSchemaType, ValidationOptions}
324
300
  import zio.blocks.chunk.ChunkMap
325
301
 
326
302
  val schema = JsonSchema.obj(
@@ -347,25 +323,16 @@ schema.check(invalidJson) // Some(SchemaError(...))
347
323
  // Using conforms() - returns Boolean
348
324
  schema.conforms(validJson) // true
349
325
  schema.conforms(invalidJson) // false
350
- ```
351
-
352
- ### Validation Options
353
-
354
- Control validation behavior:
355
-
356
- ```scala
357
- import zio.blocks.schema.json.{JsonSchema, Json, ValidationOptions}
358
326
 
359
- val schema = JsonSchema.string(format = Some("email"))
360
- val value = Json.String("not-an-email")
327
+ // Control validation behavior with ValidationOptions
328
+ val emailSchema = JsonSchema.string(format = Some("email"))
329
+ val invalidEmail = Json.String("not-an-email")
361
330
 
362
331
  // With format validation (default)
363
- val strictOptions = ValidationOptions.formatAssertion
364
- schema.check(value, strictOptions) // Some(error)
332
+ emailSchema.check(invalidEmail, ValidationOptions.formatAssertion) // Some(error)
365
333
 
366
334
  // Without format validation (format as annotation only)
367
- val lenientOptions = ValidationOptions.annotationOnly
368
- schema.check(value, lenientOptions) // None
335
+ emailSchema.check(invalidEmail, ValidationOptions.annotationOnly) // None
369
336
  ```
370
337
 
371
338
  ### Error Messages