@@ -27,9 +27,10 @@ public static function fromShorthand(array $shorthand, ?string $name = null): Ty
2727 /**
2828 * @param array<string, mixed> $definition
2929 * @param string|null $name
30+ * @param array<string, TypeSet> $rootDefinitions
3031 * @return TypeSet
3132 */
32- public static function fromDefinition (array $ definition , ?string $ name = null ): TypeSet
33+ public static function fromDefinition (array $ definition , ?string $ name = null , array $ rootDefinitions = [] ): TypeSet
3334 {
3435 if (! isset ($ definition ['type ' ])) {
3536 switch (true ) {
@@ -86,22 +87,22 @@ public static function fromDefinition(array $definition, ?string $name = null):
8687 $ types [] = BooleanType::fromDefinition ($ definition , $ name );
8788 break ;
8889 case 'object ' :
89- $ types [] = ObjectType::fromDefinition ($ definition , $ name );
90+ $ types [] = ObjectType::fromDefinition ($ definition , $ name, $ rootDefinitions );
9091 break ;
9192 case 'array ' :
92- $ types [] = ArrayType::fromDefinition ($ definition , $ name );
93+ $ types [] = ArrayType::fromDefinition ($ definition , $ name, $ rootDefinitions );
9394 break ;
9495 case 'oneOf ' :
95- $ types [] = OneOfType::fromDefinition ($ definition , $ name );
96+ $ types [] = OneOfType::fromDefinition ($ definition , $ name, $ rootDefinitions );
9697 break ;
9798 case 'anyOf ' :
98- $ types [] = AnyOfType::fromDefinition ($ definition , $ name );
99+ $ types [] = AnyOfType::fromDefinition ($ definition , $ name, $ rootDefinitions );
99100 break ;
100101 case 'allOf ' :
101- $ types [] = AllOfType::fromDefinition ($ definition , $ name );
102+ $ types [] = AllOfType::fromDefinition ($ definition , $ name, $ rootDefinitions );
102103 break ;
103104 case 'not ' :
104- $ types [] = NotType::fromDefinition ($ definition , $ name );
105+ $ types [] = NotType::fromDefinition ($ definition , $ name, $ rootDefinitions );
105106 break ;
106107 case 'const ' :
107108 $ types [] = ConstType::fromDefinition ($ definition , $ name );
@@ -122,12 +123,89 @@ public static function fromDefinition(array $definition, ?string $name = null):
122123 throw new \RuntimeException ('Could not determine type of JSON schema ' );
123124 }
124125
126+ $ typeSet = new TypeSet (...$ types );
127+
125128 foreach ($ types as $ type ) {
126129 if ($ type instanceof NullableAware) {
127130 $ type ->setNullable ($ isNullable );
128131 }
129132 }
130133
131- return new TypeSet (...$ types );
134+ self ::populateReferences ($ typeSet );
135+
136+ return $ typeSet ;
137+ }
138+
139+ /**
140+ * @param TypeSet $typeSet
141+ * @param array<string, TypeSet> $rootDefinitions
142+ */
143+ private static function populateReferences (TypeSet $ typeSet , array $ rootDefinitions = []): void
144+ {
145+ foreach ($ typeSet as $ typeDefinition ) {
146+ switch (true ) {
147+ case $ typeDefinition instanceof ObjectType:
148+ foreach ($ typeDefinition ->definitions () as $ property ) {
149+ self ::populateReferences ($ property , $ typeDefinition ->definitions ());
150+ }
151+ foreach ($ typeDefinition ->properties () as $ property ) {
152+ if (\count ($ typeDefinition ->definitions ()) > 0 ) {
153+ self ::populateReferences ($ property , $ typeDefinition ->definitions ());
154+ }
155+ if (\count ($ rootDefinitions ) > 0 ) {
156+ self ::populateReferences ($ property , $ rootDefinitions );
157+ }
158+ }
159+ $ additionalProperties = $ typeDefinition ->additionalProperties ();
160+
161+ if ($ additionalProperties instanceof TypeSet) {
162+ if (\count ($ typeDefinition ->definitions ()) > 0 ) {
163+ self ::populateReferences ($ additionalProperties , $ typeDefinition ->definitions ());
164+ }
165+ if (\count ($ rootDefinitions ) > 0 ) {
166+ self ::populateReferences ($ additionalProperties , $ rootDefinitions );
167+ }
168+ }
169+ break ;
170+ case $ typeDefinition instanceof ArrayType:
171+ foreach ($ typeDefinition ->definitions () as $ property ) {
172+ self ::populateReferences ($ property , $ typeDefinition ->definitions ());
173+ }
174+ foreach ($ typeDefinition ->items () as $ item ) {
175+ if (\count ($ typeDefinition ->definitions ()) > 0 ) {
176+ self ::populateReferences ($ item , $ typeDefinition ->definitions ());
177+ }
178+ if (\count ($ rootDefinitions ) > 0 ) {
179+ self ::populateReferences ($ item , $ rootDefinitions );
180+ }
181+ }
182+ break ;
183+ case $ typeDefinition instanceof NotType:
184+ if (\count ($ rootDefinitions ) > 0 ) {
185+ self ::populateReferences ($ typeDefinition ->getTypeSet (), $ rootDefinitions );
186+ }
187+ break ;
188+ case $ typeDefinition instanceof OfType:
189+ foreach ($ typeDefinition ->getTypeSets () as $ item ) {
190+ if (\count ($ rootDefinitions ) > 0 ) {
191+ self ::populateReferences ($ item , $ rootDefinitions );
192+ }
193+ }
194+ break ;
195+ case $ typeDefinition instanceof ReferenceType:
196+ $ referencePath = \explode ('/ ' , $ typeDefinition ->ref ());
197+ $ name = \array_pop ($ referencePath );
198+
199+ $ resolvedType = $ rootDefinitions [$ name ] ?? null ;
200+
201+ if ($ resolvedType !== null ) {
202+ $ typeDefinition ->setResolvedType (clone $ resolvedType );
203+ $ typeDefinition ->setIsRequired ($ typeDefinition ->isRequired ());
204+ }
205+ break ;
206+ default :
207+ break ;
208+ }
209+ }
132210 }
133211}
0 commit comments