2020use Symfony \Component \Config \Definition \NodeInterface ;
2121use Symfony \Component \Config \Definition \NumericNode ;
2222use Symfony \Component \Config \Definition \PrototypedArrayNode ;
23- use Symfony \Component \Config \Definition \ScalarNode ;
2423use Symfony \Component \Config \Definition \StringNode ;
2524use Symfony \Component \Config \Definition \VariableNode ;
2625
2726/**
2827 * Generates a JSON Schema from a Node definition.
2928 *
30- * @internal
29+ * @author Jérôme Tamarelle<jerome@tamarelle.net>
3130 */
3231final class JsonSchemaGenerator
3332{
@@ -36,109 +35,107 @@ final class JsonSchemaGenerator
3635 *
3736 * @param array<string, mixed> $meta Additional attributes to include in the schema root
3837 */
39- public function generate (NodeInterface $ node , array $ meta = []): \ stdClass
38+ public function generate (NodeInterface $ node , array $ meta = []): array
4039 {
41- return ( object ) [
40+ return [
4241 '$schema ' => 'http://json-schema.org/draft-07/schema ' ,
4342 ... $ meta ,
44- ... ( array ) $ this ->generateNode ($ node ),
43+ ... $ this ->generateNode ($ node ),
4544 ];
4645 }
4746
48- public function generateNode (NodeInterface $ node ): \ stdClass
47+ public function generateNode (NodeInterface $ node ): array
4948 {
5049 if ($ node instanceof PrototypedArrayNode) {
5150 $ prototypeSchema = $ this ->generateNode ($ node ->getPrototype ());
5251
5352 if ($ node ->getKeyAttribute ()) {
54- $ schema = ( object ) [
53+ $ schema = [
5554 'type ' => 'object ' ,
5655 'additionalProperties ' => $ prototypeSchema ,
5756 ];
5857
5958 if ($ node ->getMinNumberOfElements ()) {
60- $ schema-> minProperties = $ node ->getMinNumberOfElements ();
59+ $ schema[ ' minProperties ' ] = $ node ->getMinNumberOfElements ();
6160 }
6261 } else {
63- $ schema = ( object ) [
62+ $ schema = [
6463 'type ' => 'array ' ,
6564 'items ' => $ prototypeSchema
6665 ];
6766
6867 if ($ node ->getMinNumberOfElements ()) {
69- $ schema-> minItems = $ node ->getMinNumberOfElements ();
68+ $ schema[ ' minItems ' ] = $ node ->getMinNumberOfElements ();
7069 }
7170 }
7271 } elseif ($ node instanceof ArrayNode) {
73- $ schema = ( object ) ['type ' => ['object ' ]];
72+ $ schema = ['type ' => ['object ' ]];
7473 $ children = $ node ->getChildren ();
7574 foreach ($ children as $ child ) {
76- $ schema-> properties ??= new \ stdClass () ;
77- $ schema-> properties ->{ $ child ->getName ()} = $ this ->generateNode ($ child );
75+ $ schema[ ' properties ' ] ??= [] ;
76+ $ schema[ ' properties ' ][ $ child ->getName ()] = $ this ->generateNode ($ child );
7877 if ($ child ->isRequired ()) {
79- $ schema-> required ??= [];
80- $ schema-> required [] = $ child ->getName ();
78+ $ schema[ ' required ' ] ??= [];
79+ $ schema[ ' required ' ] [] = $ child ->getName ();
8180 }
8281 }
8382
84- if (property_exists ($ schema, 'properties ' )) {
83+ if (isset ($ schema[ 'properties ' ] )) {
8584 if ($ node ->shouldIgnoreExtraKeys ()) {
86- $ schema-> additionalProperties = true ;
85+ $ schema[ ' additionalProperties ' ] = true ;
8786 } else {
88- $ schema-> additionalProperties = false ;
87+ $ schema[ ' additionalProperties ' ] = false ;
8988 }
9089 }
9190 } elseif ($ node instanceof BooleanNode) {
92- $ schema = ( object ) ['type ' => ['boolean ' ]];
91+ $ schema = ['type ' => ['boolean ' ]];
9392
9493 if ($ node ->isNullable ()) {
95- $ schema-> type [] = 'null ' ;
94+ $ schema[ ' type ' ] [] = 'null ' ;
9695 }
9796 } elseif ($ node instanceof StringNode) {
98- $ schema = ( object ) ['type ' => ['string ' ]];
97+ $ schema = ['type ' => ['string ' ]];
9998 } elseif ($ node instanceof EnumNode) {
100- $ schema = ( object ) [
99+ $ schema = [
101100 '$anyOf ' => [
102- ( object ) ['enum ' => array_map (static function (mixed $ case ): string |int |float |bool |null {
101+ ['enum ' => array_map (static function (mixed $ case ): string |int |float |bool |null {
103102 if ($ case instanceof \UnitEnum) {
104103 return \sprintf ('!php/enum %s::%s ' , $ case ::class, $ case ->name );
105104 }
106105
107106 return $ case ;
108107 }, $ node ->getValues ())],
109- ( object ) ['type ' => 'null ' ],
108+ ['type ' => 'null ' ],
110109 ],
111110 ];
112111 } elseif ($ node instanceof NumericNode) {
113- $ schema = ( object ) ['type ' => $ node instanceof IntegerNode ? ['integer ' ] : ['number ' ]];
112+ $ schema = ['type ' => $ node instanceof IntegerNode ? ['integer ' ] : ['number ' ]];
114113
115114 if (null !== $ node ->getMin ()) {
116- $ schema-> minimum = $ node ->getMin ();
115+ $ schema[ ' minimum ' ] = $ node ->getMin ();
117116 }
118117
119118 if (null !== $ node ->getMax ()) {
120- $ schema-> maximum = $ node ->getMax ();
119+ $ schema[ ' maximum ' ] = $ node ->getMax ();
121120 }
122- } elseif ($ node instanceof ScalarNode) {
123- $ schema = (object ) ['type ' => ['array ' , 'object ' , 'string ' , 'number ' , 'boolean ' , 'null ' ]];
124121 } elseif ($ node instanceof VariableNode) {
125- $ schema = ( object ) ['type ' => null ];
122+ $ schema = ['type ' => [ ' array ' , ' object ' , ' string ' , ' number ' , ' boolean ' , ' null ' ] ];
126123 } else {
127- $ schema = ( object ) ['type ' => ['null ' ]];
124+ $ schema = ['type ' => ['null ' ]];
128125 }
129126
130127 if ($ node instanceof BaseNode) {
131128 $ normalizedTypes = array_diff ($ node ->getNormalizedTypes (), [ExprBuilder::TYPE_ANY , ExprBuilder::TYPE_ARRAY ]);
132129
133- if (isset ($ schema-> type ) && $ node ->hasDefaultValue () && $ node ->getDefaultValue () === null ) {
130+ if (isset ($ schema[ ' type ' ] ) && $ node ->hasDefaultValue () && $ node ->getDefaultValue () === null ) {
134131 $ normalizedTypes [] = 'null ' ;
135132 }
136133
137134 if ($ normalizedTypes ) {
138- $ schema = ( object ) [
135+ $ schema = [
139136 '$anyOf ' => [
140137 $ schema ,
141- ( object ) [
138+ [
142139 'type ' => array_values (
143140 array_unique (
144141 array_map (fn ($ type ) => match ($ type ) {
@@ -156,32 +153,32 @@ public function generateNode(NodeInterface $node): \stdClass
156153 ];
157154 }
158155
159- if (is_array ($ schema-> type ?? null )) {
160- $ schema-> type = array_values (array_unique ($ schema-> type ));
156+ if (is_array ($ schema[ ' type ' ] ?? null )) {
157+ $ schema[ ' type ' ] = array_values (array_unique ($ schema[ ' type ' ] ));
161158 }
162159
163160 if ($ node ->hasDefaultValue () && !($ node instanceof ArrayNode && $ node ->getDefaultValue () === [])) {
164- $ schema-> default = $ node ->getDefaultValue ();
161+ $ schema[ ' default ' ] = $ node ->getDefaultValue ();
165162 }
166163
167164 if ($ node ->getInfo ()) {
168- $ schema-> description = $ node ->getInfo ();
165+ $ schema[ ' description ' ] = $ node ->getInfo ();
169166 }
170167
171168 if ($ node ->getExample ()) {
172- $ schema-> examples = [$ node ->getExample ()];
169+ $ schema[ ' examples ' ] = [$ node ->getExample ()];
173170 }
174171
175172 if ($ node ->isDeprecated ()) {
176- $ schema-> deprecated = true ;
177- $ schema-> deprecationMessage = $ node ->getDeprecationMessage ($ node );
173+ $ schema[ ' deprecated ' ] = true ;
174+ $ schema[ ' deprecationMessage ' ] = $ node ->getDeprecationMessage ($ node );
178175 }
179176 }
180177
181- if (empty ($ schema-> type )) {
182- unset($ schema-> type );
183- } elseif (is_array ($ schema-> type ) && count ($ schema-> type ) === 1 ) {
184- $ schema-> type = $ schema-> type [0 ];
178+ if (empty ($ schema[ ' type ' ] )) {
179+ unset($ schema[ ' type ' ] );
180+ } elseif (is_array ($ schema[ ' type ' ] ) && count ($ schema[ ' type ' ] ) === 1 ) {
181+ $ schema[ ' type ' ] = $ schema[ ' type ' ] [0 ];
185182 }
186183
187184 return $ schema ;
0 commit comments