...

Source file src/github.com/99designs/gqlgen/api/generate.go

Documentation: github.com/99designs/gqlgen/api

     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  }
   148  

View as plain text