@@ -81,10 +81,13 @@ func (t *transformer) loadPreDefinedTypes(obj map[string]interface{}) error {
8181
8282 // Build dependencies and construct the schema
8383 for k , v := range obj {
84- dependencies := extractDependenciesFromMap (v )
84+ dependencies , err := extractDependenciesFromMap (v )
85+ if err != nil {
86+ return fmt .Errorf ("failed to extract dependencies for type %s: %w" , k , err )
87+ }
8588
8689 // Add dependencies to the DAG and check for cycles
87- err : = dagInstance .AddDependencies (k , dependencies )
90+ err = dagInstance .AddDependencies (k , dependencies )
8891 if err != nil {
8992 var cycleErr * dag.CycleError [string ]
9093 if errors .As (err , & cycleErr ) {
@@ -123,51 +126,87 @@ func (t *transformer) loadPreDefinedTypes(obj map[string]interface{}) error {
123126 return nil
124127}
125128
126- // Define the set of basic types as
127- // defined in https://kro.run/docs/concepts/simple-schema#basic-types
128- var excludedTypes = map [string ]struct {}{
129- "string" : {},
130- "integer" : {},
131- "bool" : {},
132- "float" : {},
133- "object" : {},
129+ func extractDependenciesFromMap (obj interface {}) (dependencies []string , err error ) {
130+ dependenciesSet := sets.Set [string ]{}
131+
132+ // Extract dependencies using a helper function
133+ if rootMap , ok := obj .(map [string ]interface {}); ok {
134+ err := parseMap (rootMap , dependenciesSet )
135+ if err != nil {
136+ return nil , err
137+ }
138+ }
139+ return dependenciesSet .UnsortedList (), nil
134140}
135141
136- func extractDependenciesFromMap (obj interface {}) []string {
137- dependencies := sets.Set [string ]{}
138-
139- // Use a recursive helper function to traverse the map and extract dependencies
140- var parseMap func (map [string ]interface {})
141- parseMap = func (m map [string ]interface {}) {
142- for _ , value := range m {
143- switch v := value .(type ) {
144- case string :
145- // Strip array prefixes like "[]"
146- trimmed := strings .TrimPrefix (v , "[]" )
147-
148- // Filter out primitive types
149- if _ , isExcluded := excludedTypes [trimmed ]; ! isExcluded {
150- dependencies .Insert (trimmed )
151- }
152- case map [string ]interface {}:
153- // Recursively parse nested maps
154- parseMap (v )
155- case []interface {}:
156- // Handle slices of types (e.g., []string or [][nested type])
157- for _ , elem := range v {
158- if nestedMap , ok := elem .(map [string ]interface {}); ok {
159- parseMap (nestedMap )
160- }
161- }
142+ func handleStringType (v string , dependencies sets.Set [string ]) error {
143+ // Check if the value is an atomic type
144+ if isAtomicType (v ) {
145+ return nil
146+ }
147+ // Check if the value is a collection type
148+ if isCollectionType (v ) {
149+ if isSliceType (v ) {
150+ // It is a slice, we add the type as dependency
151+ elementType , err := parseSliceType (v )
152+ if err != nil {
153+ return fmt .Errorf ("Failed to parse slice type %s: %w" , v , err )
154+ }
155+ if ! isAtomicType (elementType ) {
156+ dependencies .Insert (elementType )
162157 }
158+ return nil
159+ } else if isMapType (v ) {
160+ keyType , valueType , err := parseMapType (v )
161+ if err != nil {
162+ return fmt .Errorf ("Failed to parse map type %s: %w" , v , err )
163+ }
164+ // Only strings are supported as map keys
165+ if keyType != keyTypeString {
166+ return fmt .Errorf ("unsupported key type for maps, only strings are supported key types: %s" , keyType )
167+ }
168+ // If the value is not an atomic type, add to dependencies
169+ if ! isAtomicType (valueType ) {
170+ dependencies .Insert (strings .TrimPrefix (valueType , "[]" ))
171+ }
172+ return nil
163173 }
164174 }
165175
166- if rootMap , ok := obj .(map [string ]interface {}); ok {
167- parseMap (rootMap )
176+ // If the type is object, we do not add any dependency
177+ // As unstructured objects are not validated https://kro.run/docs/concepts/simple-schema#unstructured-objects
178+ if isObjectType (v ) {
179+ return nil
168180 }
181+ // At this point, we have a new custom type, we add it as dependency
182+ dependencies .Insert (v )
183+ return nil
184+ }
169185
170- return dependencies .UnsortedList ()
186+ func parseMap (m map [string ]interface {}, dependencies sets.Set [string ]) (err error ) {
187+
188+ for _ , value := range m {
189+ switch v := value .(type ) {
190+ case map [string ]interface {}:
191+ // Recursively parse nested maps
192+ if err := parseMap (v , dependencies ); err != nil {
193+ return err
194+ }
195+ case []interface {}:
196+ // Handle slices of types (e.g., []string or [][nested type])
197+ for key , elem := range v {
198+ print (key )
199+ if nestedMap , ok := elem .(map [string ]interface {}); ok {
200+ parseMap (nestedMap , dependencies )
201+ } else {
202+ return fmt .Errorf ("unexpected type in slice: %T" , elem )
203+ }
204+ }
205+ case string :
206+ handleStringType (v , dependencies )
207+ }
208+ }
209+ return nil
171210}
172211
173212// buildOpenAPISchema builds an OpenAPI schema from the given object
@@ -262,7 +301,7 @@ func (tf *transformer) handleMapType(key, fieldType string) (*extv1.JSONSchemaPr
262301 return nil , fmt .Errorf ("failed to parse map type for %s: %w" , key , err )
263302 }
264303 if keyType != keyTypeString {
265- return nil , fmt .Errorf ("unsupported key type for maps: %s" , keyType )
304+ return nil , fmt .Errorf ("unsupported key type for maps, only strings are supported key types : %s" , keyType )
266305 }
267306
268307 fieldJSONSchemaProps := & extv1.JSONSchemaProps {
0 commit comments