github.com/rzurga/go-swagger@v0.28.1-0.20211109195225-5d1f453ffa3a/generator/media.go (about)

     1  package generator
     2  
     3  import (
     4  	"regexp"
     5  	"sort"
     6  	"strings"
     7  
     8  	"github.com/go-openapi/runtime"
     9  	"github.com/go-openapi/swag"
    10  )
    11  
    12  const jsonSerializer = "json"
    13  
    14  var mediaTypeNames = map[*regexp.Regexp]string{
    15  	regexp.MustCompile("application/.*json"):                jsonSerializer,
    16  	regexp.MustCompile("application/.*yaml"):                "yaml",
    17  	regexp.MustCompile("application/.*protobuf"):            "protobuf",
    18  	regexp.MustCompile("application/.*capnproto"):           "capnproto",
    19  	regexp.MustCompile("application/.*thrift"):              "thrift",
    20  	regexp.MustCompile("(?:application|text)/.*xml"):        "xml",
    21  	regexp.MustCompile("text/.*markdown"):                   "markdown",
    22  	regexp.MustCompile("text/.*html"):                       "html",
    23  	regexp.MustCompile("text/.*csv"):                        "csv",
    24  	regexp.MustCompile("text/.*tsv"):                        "tsv",
    25  	regexp.MustCompile("text/.*javascript"):                 "js",
    26  	regexp.MustCompile("text/.*css"):                        "css",
    27  	regexp.MustCompile("text/.*plain"):                      "txt",
    28  	regexp.MustCompile("application/.*octet-stream"):        "bin",
    29  	regexp.MustCompile("application/.*tar"):                 "tar",
    30  	regexp.MustCompile("application/.*gzip"):                "gzip",
    31  	regexp.MustCompile("application/.*gz"):                  "gzip",
    32  	regexp.MustCompile("application/.*raw-stream"):          "bin",
    33  	regexp.MustCompile("application/x-www-form-urlencoded"): "urlform",
    34  	regexp.MustCompile("application/javascript"):            "txt",
    35  	regexp.MustCompile("multipart/form-data"):               "multipartform",
    36  	regexp.MustCompile("image/.*"):                          "bin",
    37  	regexp.MustCompile("audio/.*"):                          "bin",
    38  	regexp.MustCompile("application/pdf"):                   "bin",
    39  }
    40  
    41  var knownProducers = map[string]string{
    42  	jsonSerializer:  "runtime.JSONProducer()",
    43  	"yaml":          "yamlpc.YAMLProducer()",
    44  	"xml":           "runtime.XMLProducer()",
    45  	"txt":           "runtime.TextProducer()",
    46  	"bin":           "runtime.ByteStreamProducer()",
    47  	"urlform":       "runtime.DiscardProducer",
    48  	"multipartform": "runtime.DiscardProducer",
    49  }
    50  
    51  var knownConsumers = map[string]string{
    52  	jsonSerializer:  "runtime.JSONConsumer()",
    53  	"yaml":          "yamlpc.YAMLConsumer()",
    54  	"xml":           "runtime.XMLConsumer()",
    55  	"txt":           "runtime.TextConsumer()",
    56  	"bin":           "runtime.ByteStreamConsumer()",
    57  	"urlform":       "runtime.DiscardConsumer",
    58  	"multipartform": "runtime.DiscardConsumer",
    59  }
    60  
    61  func wellKnownMime(tn string) (string, bool) {
    62  	for k, v := range mediaTypeNames {
    63  		if k.MatchString(tn) {
    64  			return v, true
    65  		}
    66  	}
    67  	return "", false
    68  }
    69  
    70  func mediaMime(orig string) string {
    71  	return strings.SplitN(orig, ";", 2)[0]
    72  }
    73  
    74  func mediaParameters(orig string) string {
    75  	parts := strings.SplitN(orig, ";", 2)
    76  	if len(parts) < 2 {
    77  		return ""
    78  	}
    79  	return parts[1]
    80  }
    81  
    82  func (a *appGenerator) makeSerializers(mediaTypes []string, known func(string) (string, bool)) (GenSerGroups, bool) {
    83  	supportsJSON := false
    84  	uniqueSerializers := make(map[string]*GenSerializer, len(mediaTypes))
    85  	uniqueSerializerGroups := make(map[string]*GenSerGroup, len(mediaTypes))
    86  
    87  	// build all required serializers
    88  	for _, media := range mediaTypes {
    89  		key := mediaMime(media)
    90  		nm, ok := wellKnownMime(key)
    91  		if !ok {
    92  			// keep this serializer named, even though its implementation is empty (cf. #1557)
    93  			nm = key
    94  		}
    95  		name := swag.ToJSONName(nm)
    96  		impl, _ := known(name)
    97  
    98  		ser, ok := uniqueSerializers[key]
    99  		if !ok {
   100  			ser = &GenSerializer{
   101  				AppName:        a.Name,
   102  				ReceiverName:   a.Receiver,
   103  				Name:           name,
   104  				MediaType:      key,
   105  				Implementation: impl,
   106  				Parameters:     []string{},
   107  			}
   108  			uniqueSerializers[key] = ser
   109  		}
   110  		// provide all known parameters (currently unused by codegen templates)
   111  		if params := strings.TrimSpace(mediaParameters(media)); params != "" {
   112  			found := false
   113  			for _, p := range ser.Parameters {
   114  				if params == p {
   115  					found = true
   116  					break
   117  				}
   118  			}
   119  			if !found {
   120  				ser.Parameters = append(ser.Parameters, params)
   121  			}
   122  		}
   123  
   124  		uniqueSerializerGroups[name] = &GenSerGroup{
   125  			GenSerializer: GenSerializer{
   126  				AppName:        a.Name,
   127  				ReceiverName:   a.Receiver,
   128  				Name:           name,
   129  				Implementation: impl,
   130  			},
   131  		}
   132  	}
   133  
   134  	if len(uniqueSerializers) == 0 {
   135  		impl, _ := known(jsonSerializer)
   136  		uniqueSerializers[runtime.JSONMime] = &GenSerializer{
   137  			AppName:        a.Name,
   138  			ReceiverName:   a.Receiver,
   139  			Name:           jsonSerializer,
   140  			MediaType:      runtime.JSONMime,
   141  			Implementation: impl,
   142  			Parameters:     []string{},
   143  		}
   144  		uniqueSerializerGroups[jsonSerializer] = &GenSerGroup{
   145  			GenSerializer: GenSerializer{
   146  				AppName:        a.Name,
   147  				ReceiverName:   a.Receiver,
   148  				Name:           jsonSerializer,
   149  				Implementation: impl,
   150  			},
   151  		}
   152  		supportsJSON = true
   153  	}
   154  
   155  	// group serializers by consumer/producer to serve several mime media types
   156  	serializerGroups := make(GenSerGroups, 0, len(uniqueSerializers))
   157  
   158  	for _, group := range uniqueSerializerGroups {
   159  		if group.Name == jsonSerializer {
   160  			supportsJSON = true
   161  		}
   162  		serializers := make(GenSerializers, 0, len(uniqueSerializers))
   163  		for _, ser := range uniqueSerializers {
   164  			if group.Name == ser.Name {
   165  				sort.Strings(ser.Parameters)
   166  				serializers = append(serializers, *ser)
   167  			}
   168  		}
   169  		sort.Sort(serializers)
   170  		group.AllSerializers = serializers // provides the full list of mime media types for this serializer group
   171  		serializerGroups = append(serializerGroups, *group)
   172  	}
   173  	sort.Sort(serializerGroups)
   174  	return serializerGroups, supportsJSON
   175  }
   176  
   177  func (a *appGenerator) makeConsumes() (GenSerGroups, bool) {
   178  	// builds a codegen struct from all consumes in the spec
   179  	return a.makeSerializers(a.Analyzed.RequiredConsumes(), func(media string) (string, bool) {
   180  		c, ok := knownConsumers[media]
   181  		return c, ok
   182  	})
   183  }
   184  
   185  func (a *appGenerator) makeProduces() (GenSerGroups, bool) {
   186  	// builds a codegen struct from all produces in the spec
   187  	return a.makeSerializers(a.Analyzed.RequiredProduces(), func(media string) (string, bool) {
   188  		p, ok := knownProducers[media]
   189  		return p, ok
   190  	})
   191  }