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 }