github.com/99designs/gqlgen@v0.17.45/api/generate.go (about) 1 package api 2 3 import ( 4 "fmt" 5 "regexp" 6 "syscall" 7 8 "github.com/99designs/gqlgen/codegen" 9 "github.com/99designs/gqlgen/codegen/config" 10 "github.com/99designs/gqlgen/plugin" 11 "github.com/99designs/gqlgen/plugin/federation" 12 "github.com/99designs/gqlgen/plugin/modelgen" 13 "github.com/99designs/gqlgen/plugin/resolvergen" 14 ) 15 16 func Generate(cfg *config.Config, option ...Option) error { 17 _ = syscall.Unlink(cfg.Exec.Filename) 18 if cfg.Model.IsDefined() { 19 _ = syscall.Unlink(cfg.Model.Filename) 20 } 21 22 plugins := []plugin.Plugin{} 23 if cfg.Model.IsDefined() { 24 plugins = append(plugins, modelgen.New()) 25 } 26 plugins = append(plugins, resolvergen.New()) 27 if cfg.Federation.IsDefined() { 28 if cfg.Federation.Version == 0 { // default to using the user's choice of version, but if unset, try to sort out which federation version to use 29 urlRegex := regexp.MustCompile(`(?s)@link.*\(.*url:.*?"(.*?)"[^)]+\)`) // regex to grab the url of a link directive, should it exist 30 versionRegex := regexp.MustCompile(`v(\d+).(\d+)$`) // regex to grab the version number from a url 31 // check the sources, and if one is marked as federation v2, we mark the entirety to be generated using that format 32 for _, v := range cfg.Sources { 33 cfg.Federation.Version = 1 34 urlString := urlRegex.FindStringSubmatch(v.Input) 35 // e.g. urlString[1] == "https://specs.apollo.dev/federation/v2.7" 36 if urlString != nil { 37 matches := versionRegex.FindStringSubmatch(urlString[1]) 38 if matches[1] == "2" { 39 cfg.Federation.Version = 2 40 break 41 } 42 } 43 } 44 } 45 plugins = append([]plugin.Plugin{federation.New(cfg.Federation.Version)}, plugins...) 46 } 47 48 for _, o := range option { 49 o(cfg, &plugins) 50 } 51 52 for _, p := range plugins { 53 if inj, ok := p.(plugin.EarlySourceInjector); ok { 54 if s := inj.InjectSourceEarly(); s != nil { 55 cfg.Sources = append(cfg.Sources, s) 56 } 57 } 58 } 59 60 if err := cfg.LoadSchema(); err != nil { 61 return fmt.Errorf("failed to load schema: %w", err) 62 } 63 64 for _, p := range plugins { 65 if inj, ok := p.(plugin.LateSourceInjector); ok { 66 if s := inj.InjectSourceLate(cfg.Schema); s != nil { 67 cfg.Sources = append(cfg.Sources, s) 68 } 69 } 70 } 71 72 // LoadSchema again now we have everything 73 if err := cfg.LoadSchema(); err != nil { 74 return fmt.Errorf("failed to load schema: %w", err) 75 } 76 77 if err := cfg.Init(); err != nil { 78 return fmt.Errorf("generating core failed: %w", err) 79 } 80 81 for _, p := range plugins { 82 if mut, ok := p.(plugin.ConfigMutator); ok { 83 err := mut.MutateConfig(cfg) 84 if err != nil { 85 return fmt.Errorf("%s: %w", p.Name(), err) 86 } 87 } 88 } 89 // Merge again now that the generated models have been injected into the typemap 90 data_plugins := make([]interface{}, len(plugins)) 91 for index := range plugins { 92 data_plugins[index] = plugins[index] 93 } 94 data, err := codegen.BuildData(cfg, data_plugins...) 95 if err != nil { 96 return fmt.Errorf("merging type systems failed: %w", err) 97 } 98 99 if err = codegen.GenerateCode(data); err != nil { 100 return fmt.Errorf("generating core failed: %w", err) 101 } 102 103 if !cfg.SkipModTidy { 104 if err = cfg.Packages.ModTidy(); err != nil { 105 return fmt.Errorf("tidy failed: %w", err) 106 } 107 } 108 109 for _, p := range plugins { 110 if mut, ok := p.(plugin.CodeGenerator); ok { 111 err := mut.GenerateCode(data) 112 if err != nil { 113 return fmt.Errorf("%s: %w", p.Name(), err) 114 } 115 } 116 } 117 118 if err = codegen.GenerateCode(data); err != nil { 119 return fmt.Errorf("generating core failed: %w", err) 120 } 121 122 if !cfg.SkipValidation { 123 if err := validate(cfg); err != nil { 124 return fmt.Errorf("validation failed: %w", err) 125 } 126 } 127 128 return nil 129 } 130 131 func validate(cfg *config.Config) error { 132 roots := []string{cfg.Exec.ImportPath()} 133 if cfg.Model.IsDefined() { 134 roots = append(roots, cfg.Model.ImportPath()) 135 } 136 137 if cfg.Resolver.IsDefined() { 138 roots = append(roots, cfg.Resolver.ImportPath()) 139 } 140 141 cfg.Packages.LoadAll(roots...) 142 errs := cfg.Packages.Errors() 143 if len(errs) > 0 { 144 return errs 145 } 146 return nil 147 }