@@ -651,6 +651,137 @@ Example:
651651}
652652~~~
653653
654+ # ### `choice` {#choice}
655+
656+ The `choice` type is used to define a "discriminated union" of types. A
657+ choice is a set of types where only one type can be selected at a time and
658+ where the selected type is determined by the value of a selector.
659+
660+ The `choice` type can declare two variants of discriminated unions that
661+ are represented differently in JSON :
662+
663+ - _Tagged unions_ : The `choice` type is represented as a JSON object with a
664+ single property whose name is the selector of the type as declared in the
665+ [`choices`]({{choices-keyword}}) map and whose value is of the selected type.
666+ - _Inline unions_ : The `choice` type is represented as a JSON object of the
667+ selected type with the selector as a property of the object.
668+
669+ # #### Tagged Unions {#tagged-unions}
670+
671+ A tagged union is declared as follows :
672+
673+ ~~~ json
674+ {
675+ " type " : " choice" ,
676+ " name " : " MyChoice" ,
677+ " choices " : {
678+ " string " : { "type": "string" },
679+ " int32 " : { "type": "int32" }
680+ }
681+ }
682+ ~~~
683+
684+ The JSON node described by the schema above is a tagged union. For the
685+ example, the following JSON node is a valid instance of the `MyChoice` type :
686+
687+ ~~~ json
688+ {
689+ " string " : " Hello, world!"
690+ }
691+ ~~~
692+
693+ or :
694+
695+ ~~~ json
696+ {
697+ " int32 " : 42
698+ }
699+
700+ # #### Inline Unions {#inline-unions}
701+
702+ Inline unions require for all type choices to extend a common base type.
703+
704+ This is expressed by using the [`$extends`]({{extends}}) keyword in the
705+ ` choice` declaration. The `$extends` keyword MUST refer to a schema that
706+ defines the base type and the base type MUST be abstract.
707+
708+ If `$extends` is present, the `selector` property declares the name of the
709+ injected property that acts as the selector for the inline union. The
710+ type of the selector property is `string`. The selector property MAY
711+ shadow a property of the base type; in this case, the base type property
712+ MUST be of type `string`.
713+
714+ The selector is defined as a property of the base type and the value of the
715+ selector property MUST be a string that matches the name of one of the
716+ options in the `choices` map.
717+
718+ Example :
719+
720+ ~~~ json
721+ {
722+ " $schema " : " https://json-structure.org/meta/core/v0/#" ,
723+ " $id " : " https://schemas.vasters.com/TypeName" ,
724+ " type " : " choice" ,
725+ " $extends " : " #/definitions/Address" ,
726+ " selector " : " addressType" ,
727+ " choices " : {
728+ " StreetAddress " : { "$ref": "#/definitions/StreetAddress" },
729+ " PostOfficeBoxAddress " : { "$ref": "#/definitions/PostOfficeBoxAddress" }
730+ },
731+ " definitions" : {
732+ " Address " : {
733+ " abstract " : true,
734+ " type " : " object" ,
735+ " properties " : {
736+ " city " : { "type": "string" },
737+ " state " : { "type": "string" },
738+ " zip " : { "type": "string" }
739+ }
740+ },
741+ " StreetAddress " : {
742+ " type " : " object" ,
743+ " $extends " : " #/definitions/Address" ,
744+ " properties " : {
745+ " street " : { "type": "string" }
746+ }
747+ },
748+ " PostOfficeBoxAddress " : {
749+ " type " : " object" ,
750+ " $extends " : " #/definitions/Address" ,
751+ " properties " : {
752+ " poBox " : { "type": "string" }
753+ }
754+ }
755+ }
756+ }
757+ ~~~
758+
759+ The JSON node described by the schema above is an inline union. This
760+ example shows a JSON node that is a street address :
761+
762+ ~~~ json
763+ {
764+ " addressType " : " StreetAddress" ,
765+ " street " : " 123 Main St" ,
766+ " city " : " Seattle" ,
767+ " state " : " WA" ,
768+ " zip " : " 98101"
769+ }
770+ ~~~
771+
772+ This example shows a JSON node that is a post office box address :
773+
774+ ~~~ json
775+ {
776+ " addressType " : " PostOfficeBoxAddress" ,
777+ " poBox " : " 1234" ,
778+ " city " : " Seattle" ,
779+ " state " : " WA" ,
780+ " zip " : " 98101"
781+ }
782+ ~~~
783+
784+
654785# # Document Structure {#document-structure}
655786
656787A JSON Structure document is a JSON object that contains schemas ({{schema}})
@@ -973,8 +1104,10 @@ specification.
9731104
9741105# ## Unions {#unions}
9751106
976- - Type unions are formed as sets of primitive types and type references. It is
977- NOT permitted to define a compound type inline inside a union.
1107+ - Non-discriminated type unions are formed as sets of primitive types and type
1108+ references. It is NOT permitted to define a compound type inline inside a
1109+ non-discriminated type union. Discriminated unions are formed as a
1110+ [`choice`]({{choice}}) type to which the rules of this section do not apply.
9781111- A type union is a composite type reference and not a standalone compound type
9791112 and is therefore not named.
9801113- The JSON node described by a schema with a type union MUST conform to at least
@@ -1206,6 +1339,38 @@ provided with a schema, each additional property MUST conform to it.
12061339}
12071340~~~
12081341
1342+ # ## The `choices` Keyword {#choices-keyword}
1343+
1344+ ` choices` defines the choices of a `choice` type. The value MUST be a map of
1345+ type names to schemas. Each type name MUST be unique within the `choices` map.
1346+
1347+ The value of each type name MUST be a schema. Inline compound types are permitted.
1348+
1349+ The `choices` keyword MUST only be used in schemas of type [`choice`]({{choice}}).
1350+
1351+ ***Example**:
1352+
1353+ ~~~ json
1354+ {
1355+ " type " : " choice" ,
1356+ " name " : " MyChoice" ,
1357+ " choices " : {
1358+ " string " : { "type": "string" },
1359+ " int32 " : { "type": "int32" }
1360+ }
1361+ }
1362+ ~~~
1363+
1364+
1365+ # ## The `selector` Keyword {#selector-keyword}
1366+
1367+ The `selector` keyword defines the name of the property that acts as the selector
1368+ for the type in a `choice` type. The value of `selector` MUST be a string.
1369+
1370+ The `selector` keyword MUST only be used in schemas of type [`choice`]({{choice}}).
1371+
1372+ See [`choice`]({{choice}}) for an example.
1373+
12091374# # Type Annotation Keywords {#type-annotation-keywords}
12101375
12111376Type annotation keywords provide additional metadata about the underlying type.
@@ -1552,6 +1717,7 @@ custom annotations or extension keywords:
15521717- ` $offers`
15531718- ` abstract`
15541719- ` additionalProperties`
1720+ - ` choices`
15551721- ` const`
15561722- ` default`
15571723- ` description`
@@ -1565,6 +1731,7 @@ custom annotations or extension keywords:
15651731- ` properties`
15661732- ` required`
15671733- ` scale`
1734+ - ` selector`
15681735- ` type`
15691736- ` values`
15701737
0 commit comments