From f8d555cca59a48df9cde2e7323ff2d500e0590a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Mon, 3 Apr 2017 22:39:37 +0200 Subject: media: Add DecodeTypes And clean up the media package. --- media/mediaType.go | 132 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 121 insertions(+), 11 deletions(-) (limited to 'media/mediaType.go') diff --git a/media/mediaType.go b/media/mediaType.go index b56904cd9..bc54986be 100644 --- a/media/mediaType.go +++ b/media/mediaType.go @@ -15,19 +15,11 @@ package media import ( "fmt" + "sort" "strings" -) - -type Types []Type -func (t Types) GetByType(tp string) (Type, bool) { - for _, tt := range t { - if strings.EqualFold(tt.Type(), tp) { - return tt, true - } - } - return Type{}, false -} + "github.com/mitchellh/mapstructure" +) // A media type (also known as MIME type and content type) is a two-part identifier for // file formats and format contents transmitted on the Internet. @@ -41,6 +33,29 @@ type Type struct { Suffix string // i.e html } +// FromTypeString creates a new Type given a type sring on the form MainType/SubType and +// an optional suffix, e.g. "text/html" or "text/html+html". +func FromString(t string) (Type, error) { + t = strings.ToLower(t) + parts := strings.Split(t, "/") + if len(parts) != 2 { + return Type{}, fmt.Errorf("cannot parse %q as a media type", t) + } + mainType := parts[0] + subParts := strings.Split(parts[1], "+") + + subType := subParts[0] + var suffix string + + if len(subParts) == 1 { + suffix = subType + } else { + suffix = subParts[1] + } + + return Type{MainType: mainType, SubType: subType, Suffix: suffix}, nil +} + // Type returns a string representing the main- and sub-type of a media type, i.e. "text/css". // Hugo will register a set of default media types. // These can be overridden by the user in the configuration, @@ -68,4 +83,99 @@ var ( TextType = Type{"text", "plain", "txt"} ) +var DefaultTypes = Types{ + CalendarType, + CSSType, + CSVType, + HTMLType, + JavascriptType, + JSONType, + RSSType, + XMLType, + TextType, +} + +func init() { + sort.Sort(DefaultTypes) +} + +type Types []Type + +func (t Types) Len() int { return len(t) } +func (t Types) Swap(i, j int) { t[i], t[j] = t[j], t[i] } +func (t Types) Less(i, j int) bool { return t[i].Type() < t[j].Type() } + +func (t Types) GetByType(tp string) (Type, bool) { + for _, tt := range t { + if strings.EqualFold(tt.Type(), tp) { + return tt, true + } + } + return Type{}, false +} + +// GetBySuffix gets a media type given as suffix, e.g. "html". +// It will return false if no format could be found, or if the suffix given +// is ambiguous. +// The lookup is case insensitive. +func (t Types) GetBySuffix(suffix string) (tp Type, found bool) { + for _, tt := range t { + if strings.EqualFold(suffix, tt.Suffix) { + if found { + // ambiguous + found = false + return + } + tp = tt + found = true + } + } + return +} + +// DecodeTypes takes a list of media type configurations and merges those, +// in ther order given, with the Hugo defaults as the last resort. +func DecodeTypes(maps ...map[string]interface{}) (Types, error) { + m := make(Types, len(DefaultTypes)) + copy(m, DefaultTypes) + + for _, mm := range maps { + for k, v := range mm { + // It may be tempting to put the full media type in the key, e.g. + // "text/css+css", but that will break the logic below. + if strings.Contains(k, "+") { + return Types{}, fmt.Errorf("media type keys cannot contain any '+' chars. Valid example is %q", "text/css") + } + + found := false + for i, vv := range m { + // Match by type, i.e. "text/css" + if strings.EqualFold(k, vv.Type()) { + // Merge it with the existing + if err := mapstructure.WeakDecode(v, &m[i]); err != nil { + return m, err + } + found = true + } + } + if !found { + mediaType, err := FromString(k) + if err != nil { + return m, err + } + + if err := mapstructure.WeakDecode(v, &mediaType); err != nil { + return m, err + } + + m = append(m, mediaType) + } + } + } + + sort.Sort(m) + + return m, nil +} + // TODO(bep) output mime.AddExtensionType -- cgit v1.2.3