Skip to content

Commit ff98f0b

Browse files
authored
Fix JSON Schema object scope intersections (#7330)
1 parent cbe1850 commit ff98f0b

9 files changed

Lines changed: 631 additions & 364 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect": patch
3+
---
4+
5+
Preserve JSON Schema object keyword scopes when importing `allOf` intersections, including closed empty objects and required-only keys. Emit intersecting index signatures without weakening their constraints, and reject object scope intersections that cannot be represented faithfully.

‎packages/effect/src/Schema.ts‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15171,15 +15171,18 @@ export interface ToJsonSchemaOptions {
1517115171
* The `options` parameter controls generation details such as additional
1517215172
* properties and synthesized check descriptions; it does not change the draft
1517315173
* target. Declarations are lowered through their `toCodecJson` or `toCodec`
15174-
* annotation when available before the representation document is compiled.
15174+
* annotation when available before the representation document is compiled. For schemas whose codec JSON AST can be
15175+
* represented exactly in JSON Schema, importing the emitted document reconstructs a schema that accepts the same JSON
15176+
* values. This is a semantic round-trip guarantee; the reconstructed AST may have a different shape.
1517515177
*
1517615178
* **Gotchas**
1517715179
*
1517815180
* JSON Schema generation is best-effort. Some Effect schema semantics cannot
1517915181
* be represented exactly in JSON Schema, and importing an emitted JSON Schema
1518015182
* may produce an equivalent approximation rather than the original schema
15181-
* shape. Opaque declarations without a structural codec are represented by an
15182-
* unconstrained JSON Schema.
15183+
* shape. Such schemas are outside the exact round-trip subset. Opaque declarations without a structural codec are
15184+
* represented by an unconstrained JSON Schema. Effect decoding may discard excess object properties by default; use
15185+
* `onExcessProperty: "error"` when comparing validation semantics with an emitted JSON Schema.
1518315186
*
1518415187
* @category converting
1518515188
* @since 4.0.0

‎packages/effect/src/SchemaRepresentation.ts‎

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -752,12 +752,21 @@ export function toMultiDocument(document: Document): MultiDocument {
752752
*
753753
* Use when you need JSON Schema output from a representation whose checks carry compiler annotations.
754754
*
755+
* **Details**
756+
*
757+
* For representation documents whose validation semantics can be expressed exactly in JSON Schema, importing the
758+
* emitted document with {@link fromJsonSchemaDocument} reconstructs a schema that accepts the same JSON values. This
759+
* is a semantic round-trip guarantee; the emitted document and reconstructed representation may have different shapes.
760+
*
755761
* **Gotchas**
756762
*
757-
* Opaque declarations are represented by an unconstrained JSON Schema. Check callback results are used directly, and
758-
* exceptions raised by a callback pass through unchanged. Callbacks must treat their input schemas as immutable. Each
759-
* returned value must be a valid JSON Schema object graph and must not be mutated after the callback returns. Local
760-
* definition references returned by callbacks are resolved together with compiler-generated references.
763+
* - Opaque declarations are represented by an unconstrained JSON Schema and are outside the exact round-trip subset.
764+
* - Check callback results are used directly, and exceptions raised by a callback pass through unchanged. Callbacks
765+
* must treat their input schemas as immutable. Each returned value must be a valid JSON Schema object graph and must
766+
* not be mutated after the callback returns.
767+
* - Local definition references returned by callbacks are resolved together with compiler-generated references.
768+
* - Effect decoding may discard excess object properties by default. Use `onExcessProperty: "error"` when comparing
769+
* validation semantics with the emitted JSON Schema.
761770
*
762771
* @see {@link toJsonSchemaMultiDocument} for multiple roots sharing definitions
763772
*
@@ -1178,12 +1187,23 @@ export function fromRepresentations(
11781187
*
11791188
* Use when you need to validate or transform values described by an external JSON Schema document.
11801189
*
1190+
* **Details**
1191+
*
1192+
* For the Draft 2020-12 subset translated exactly by this importer, compiling the imported schema through
1193+
* {@link toRepresentation} and {@link toJsonSchemaDocument} produces a document that accepts the same JSON values as
1194+
* the input. This is a semantic round-trip guarantee; keyword layout, definitions, and annotations may be normalized.
1195+
*
11811196
* **Gotchas**
11821197
*
1183-
* Import is best-effort. Built-in declarations and checks are reconstructed with importer-owned revivers. Pattern
1184-
* constraints reached during translation cause an error by default. Use `patterns: "apply"` only for trusted documents,
1185-
* or `patterns: "ignore"` to weaken validation explicitly. Callback results are used directly, and exceptions raised by a
1186-
* callback pass through unchanged.
1198+
* - Import is best-effort outside the exactly translated subset. Unsupported or ignored keywords are not covered by the
1199+
* round-trip guarantee.
1200+
* - Built-in declarations and checks are reconstructed with importer-owned revivers.
1201+
* - Pattern constraints reached during translation cause an error by default. Use `patterns: "apply"` only for trusted
1202+
* documents, or `patterns: "ignore"` to weaken validation explicitly; ignored patterns are outside the round-trip
1203+
* guarantee.
1204+
* - `onEnter` results replace the corresponding input nodes, so the round-trip guarantee applies to the rewritten
1205+
* document.
1206+
* - Callback results are used directly, and exceptions raised by a callback pass through unchanged.
11871207
*
11881208
* @see {@link fromJsonSchemaMultiDocument} for multiple roots sharing definitions
11891209
* @see {@link toRepresentation} for converting the result to a representation document

0 commit comments

Comments
 (0)