@@ -76,6 +76,8 @@ type Options struct {
7676 Profiles []string
7777 // ResourceLoaders manages support for remote resources
7878 ResourceLoaders []ResourceLoader
79+ // KnownExtensions manages x-* attribute we know and the corresponding go structs
80+ KnownExtensions map [string ]any
7981}
8082
8183// ResourceLoader is a plugable remote resource resolver
@@ -148,6 +150,7 @@ func (o *Options) clone() *Options {
148150 projectNameImperativelySet : o .projectNameImperativelySet ,
149151 Profiles : o .Profiles ,
150152 ResourceLoaders : o .ResourceLoaders ,
153+ KnownExtensions : o .KnownExtensions ,
151154 }
152155}
153156
@@ -456,7 +459,11 @@ func load(ctx context.Context, configDetails types.ConfigDetails, opts *Options,
456459 }
457460 delete (dict , "name" ) // project name set by yaml must be identified by caller as opts.projectName
458461
459- dict = groupXFieldsIntoExtensions (dict , tree .NewPath ())
462+ dict , err = processExtensions (dict , tree .NewPath (), opts .KnownExtensions )
463+ if err != nil {
464+ return nil , err
465+ }
466+
460467 err = Transform (dict , project )
461468 if err != nil {
462469 return nil , err
@@ -596,8 +603,9 @@ var userDefinedKeys = []tree.Path{
596603 "configs" ,
597604}
598605
599- func groupXFieldsIntoExtensions (dict map [string ]interface {}, p tree.Path ) map [string ]interface {} {
600- extras := map [string ]interface {}{}
606+ func processExtensions (dict map [string ]any , p tree.Path , extensions map [string ]any ) (map [string ]interface {}, error ) {
607+ extras := map [string ]any {}
608+ var err error
601609 for key , value := range dict {
602610 skip := false
603611 for _ , uk := range userDefinedKeys {
@@ -613,19 +621,35 @@ func groupXFieldsIntoExtensions(dict map[string]interface{}, p tree.Path) map[st
613621 }
614622 switch v := value .(type ) {
615623 case map [string ]interface {}:
616- dict [key ] = groupXFieldsIntoExtensions (v , p .Next (key ))
624+ dict [key ], err = processExtensions (v , p .Next (key ), extensions )
625+ if err != nil {
626+ return nil , err
627+ }
617628 case []interface {}:
618629 for i , e := range v {
619630 if m , ok := e .(map [string ]interface {}); ok {
620- v [i ] = groupXFieldsIntoExtensions (m , p .Next (strconv .Itoa (i )))
631+ v [i ], err = processExtensions (m , p .Next (strconv .Itoa (i )), extensions )
632+ if err != nil {
633+ return nil , err
634+ }
621635 }
622636 }
623637 }
624638 }
639+ for name , val := range extras {
640+ if typ , ok := extensions [name ]; ok {
641+ target := reflect .New (reflect .TypeOf (typ )).Elem ().Interface ()
642+ err = Transform (val , & target )
643+ if err != nil {
644+ return nil , err
645+ }
646+ extras [name ] = target
647+ }
648+ }
625649 if len (extras ) > 0 {
626650 dict [consts .Extensions ] = extras
627651 }
628- return dict
652+ return dict , nil
629653}
630654
631655// Transform converts the source into the target struct with compose types transformer
0 commit comments