From ebb56e8bdbfaf4f955326017e40b2805850871e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Tue, 28 Aug 2018 14:18:12 +0200 Subject: Improve minifier MIME type resolution This commit also removes the deprecated `Suffix` from MediaType. Now use `Suffixes` and put the MIME type suffix in the type, e.g. `application/svg+xml`. Fixes #5093 --- media/mediaType.go | 60 ++++++++++++++++++++++++------------------------- media/mediaType_test.go | 40 ++++++++++++++++++--------------- 2 files changed, 51 insertions(+), 49 deletions(-) (limited to 'media') diff --git a/media/mediaType.go b/media/mediaType.go index 787579956..9f5ca89ff 100644 --- a/media/mediaType.go +++ b/media/mediaType.go @@ -15,11 +15,13 @@ package media import ( "encoding/json" + "errors" "fmt" "sort" "strings" - "github.com/gohugoio/hugo/helpers" + "github.com/gohugoio/hugo/common/maps" + "github.com/mitchellh/mapstructure" ) @@ -37,10 +39,9 @@ type Type struct { MainType string `json:"mainType"` // i.e. text SubType string `json:"subType"` // i.e. html - // Deprecated in Hugo 0.44. To be renamed and unexported. - // Was earlier used both to set file suffix and to augment the MIME type. - // This had its limitations and issues. - OldSuffix string `json:"-" mapstructure:"suffix"` + // This is the optional suffix after the "+" in the MIME type, + // e.g. "xml" in "applicatiion/rss+xml". + mimeSuffix string Delimiter string `json:"delimiter"` // e.g. "." @@ -79,7 +80,7 @@ func fromString(t string) (Type, error) { suffix = subParts[1] } - return Type{MainType: mainType, SubType: subType, OldSuffix: suffix}, nil + return Type{MainType: mainType, SubType: subType, mimeSuffix: suffix}, nil } // Type returns a string representing the main- and sub-type of a media type, e.g. "text/css". @@ -91,8 +92,8 @@ func (m Type) Type() string { // Examples are // image/svg+xml // text/css - if m.OldSuffix != "" { - return fmt.Sprintf("%s/%s+%s", m.MainType, m.SubType, m.OldSuffix) + if m.mimeSuffix != "" { + return fmt.Sprintf("%s/%s+%s", m.MainType, m.SubType, m.mimeSuffix) } return fmt.Sprintf("%s/%s", m.MainType, m.SubType) @@ -130,9 +131,9 @@ var ( HTMLType = Type{MainType: "text", SubType: "html", Suffixes: []string{"html"}, Delimiter: defaultDelimiter} JavascriptType = Type{MainType: "application", SubType: "javascript", Suffixes: []string{"js"}, Delimiter: defaultDelimiter} JSONType = Type{MainType: "application", SubType: "json", Suffixes: []string{"json"}, Delimiter: defaultDelimiter} - RSSType = Type{MainType: "application", SubType: "rss", OldSuffix: "xml", Suffixes: []string{"xml"}, Delimiter: defaultDelimiter} + RSSType = Type{MainType: "application", SubType: "rss", mimeSuffix: "xml", Suffixes: []string{"xml"}, Delimiter: defaultDelimiter} XMLType = Type{MainType: "application", SubType: "xml", Suffixes: []string{"xml"}, Delimiter: defaultDelimiter} - SVGType = Type{MainType: "image", SubType: "svg", OldSuffix: "xml", Suffixes: []string{"svg"}, Delimiter: defaultDelimiter} + SVGType = Type{MainType: "image", SubType: "svg", mimeSuffix: "xml", Suffixes: []string{"svg"}, Delimiter: defaultDelimiter} TextType = Type{MainType: "text", SubType: "plain", Suffixes: []string{"txt"}, Delimiter: defaultDelimiter} OctetType = Type{MainType: "application", SubType: "octet-stream"} @@ -182,6 +183,17 @@ func (t Types) GetByType(tp string) (Type, bool) { return Type{}, false } +// BySuffix will return all media types matching a suffix. +func (t Types) BySuffix(suffix string) []Type { + var types []Type + for _, tt := range t { + if match := tt.matchSuffix(suffix); match != "" { + types = append(types, tt) + } + } + return types +} + // GetFirstBySuffix will return the first media type matching the given suffix. func (t Types) GetFirstBySuffix(suffix string) (Type, bool) { for _, tt := range t { @@ -214,9 +226,6 @@ func (t Types) GetBySuffix(suffix string) (tp Type, found bool) { } func (t Type) matchSuffix(suffix string) string { - if strings.EqualFold(suffix, t.OldSuffix) { - return t.OldSuffix - } for _, s := range t.Suffixes { if strings.EqualFold(suffix, s) { return s @@ -246,9 +255,8 @@ func (t Types) GetByMainSubType(mainType, subType string) (tp Type, found bool) return } -func suffixIsDeprecated() { - helpers.Deprecated("MediaType", "Suffix in config.toml", ` -Before Hugo 0.44 this was used both to set a custom file suffix and as way +func suffixIsRemoved() error { + return errors.New(`MediaType.Suffix is removed. Before Hugo 0.44 this was used both to set a custom file suffix and as way to augment the mediatype definition (what you see after the "+", e.g. "image/svg+xml"). This had its limitations. For one, it was only possible with one file extension per MIME type. @@ -272,16 +280,13 @@ To: [mediaTypes."my/custom-mediatype"] suffixes = ["txt"] -Hugo will still respect values set in "suffix" if no value for "suffixes" is provided, but this will be removed -in a future release. - Note that you can still get the Media Type's suffix from a template: {{ $mediaType.Suffix }}. But this will now map to the MIME type filename. -`, false) +`) } // DecodeTypes takes a list of media type configurations and merges those, // in the order given, with the Hugo defaults as the last resort. -func DecodeTypes(maps ...map[string]interface{}) (Types, error) { +func DecodeTypes(mms ...map[string]interface{}) (Types, error) { var m Types // Maps type string to Type. Type string is the full application/svg+xml. @@ -293,7 +298,7 @@ func DecodeTypes(maps ...map[string]interface{}) (Types, error) { mmm[dt.Type()] = dt } - for _, mm := range maps { + for _, mm := range mms { for k, v := range mm { var mediaType Type @@ -311,24 +316,17 @@ func DecodeTypes(maps ...map[string]interface{}) (Types, error) { } vm := v.(map[string]interface{}) + maps.ToLower(vm) _, delimiterSet := vm["delimiter"] _, suffixSet := vm["suffix"] if suffixSet { - suffixIsDeprecated() + return Types{}, suffixIsRemoved() } - // Before Hugo 0.44 we had a non-standard use of the Suffix - // attribute, and this is now deprecated (use Suffixes for file suffixes). - // But we need to keep old configurations working for a while. - if len(mediaType.Suffixes) == 0 && mediaType.OldSuffix != "" { - mediaType.Suffixes = []string{mediaType.OldSuffix} - } // The user may set the delimiter as an empty string. if !delimiterSet && len(mediaType.Suffixes) != 0 { mediaType.Delimiter = defaultDelimiter - } else if suffixSet && !delimiterSet { - mediaType.Delimiter = defaultDelimiter } mmm[k] = mediaType diff --git a/media/mediaType_test.go b/media/mediaType_test.go index 6385528ee..bf356582f 100644 --- a/media/mediaType_test.go +++ b/media/mediaType_test.go @@ -80,11 +80,19 @@ func TestGetByMainSubType(t *testing.T) { assert.False(found) } +func TestBySuffix(t *testing.T) { + assert := require.New(t) + formats := DefaultTypes.BySuffix("xml") + assert.Equal(2, len(formats)) + assert.Equal("rss", formats[0].SubType) + assert.Equal("xml", formats[1].SubType) +} + func TestGetFirstBySuffix(t *testing.T) { assert := require.New(t) f, found := DefaultTypes.GetFirstBySuffix("xml") assert.True(found) - assert.Equal(Type{MainType: "application", SubType: "rss", OldSuffix: "xml", Delimiter: ".", Suffixes: []string{"xml"}, fileSuffix: "xml"}, f) + assert.Equal(Type{MainType: "application", SubType: "rss", mimeSuffix: "xml", Delimiter: ".", Suffixes: []string{"xml"}, fileSuffix: "xml"}, f) } func TestFromTypeString(t *testing.T) { @@ -94,18 +102,18 @@ func TestFromTypeString(t *testing.T) { f, err = fromString("application/custom") require.NoError(t, err) - require.Equal(t, Type{MainType: "application", SubType: "custom", OldSuffix: "", fileSuffix: ""}, f) + require.Equal(t, Type{MainType: "application", SubType: "custom", mimeSuffix: "", fileSuffix: ""}, f) f, err = fromString("application/custom+sfx") require.NoError(t, err) - require.Equal(t, Type{MainType: "application", SubType: "custom", OldSuffix: "sfx"}, f) + require.Equal(t, Type{MainType: "application", SubType: "custom", mimeSuffix: "sfx"}, f) _, err = fromString("noslash") require.Error(t, err) f, err = fromString("text/xml; charset=utf-8") require.NoError(t, err) - require.Equal(t, Type{MainType: "text", SubType: "xml", OldSuffix: ""}, f) + require.Equal(t, Type{MainType: "text", SubType: "xml", mimeSuffix: ""}, f) require.Equal(t, "", f.Suffix()) } @@ -146,28 +154,24 @@ func TestDecodeTypes(t *testing.T) { json, found := tt.GetBySuffix("jasn") require.True(t, found) require.Equal(t, "application/json", json.String(), name) + require.Equal(t, ".jasn", json.FullSuffix()) }}, { - "Suffix from key, multiple file suffixes", + "MIME suffix in key, multiple file suffixes, custom delimiter", []map[string]interface{}{ { "application/hugo+hg": map[string]interface{}{ - "Suffixes": []string{"hg1", "hg2"}, + "suffixes": []string{"hg1", "hg2"}, + "Delimiter": "_", }}}, false, func(t *testing.T, name string, tt Types) { require.Len(t, tt, len(DefaultTypes)+1) - hg, found := tt.GetBySuffix("hg") - require.True(t, found) - require.Equal(t, "hg", hg.OldSuffix) - require.Equal(t, "hg", hg.Suffix()) - require.Equal(t, ".hg", hg.FullSuffix()) - require.Equal(t, "application/hugo+hg", hg.String(), name) - hg, found = tt.GetBySuffix("hg2") + hg, found := tt.GetBySuffix("hg2") require.True(t, found) - require.Equal(t, "hg", hg.OldSuffix) + require.Equal(t, "hg", hg.mimeSuffix) require.Equal(t, "hg2", hg.Suffix()) - require.Equal(t, ".hg2", hg.FullSuffix()) + require.Equal(t, "_hg2", hg.FullSuffix()) require.Equal(t, "application/hugo+hg", hg.String(), name) hg, found = tt.GetByType("application/hugo+hg") @@ -178,8 +182,8 @@ func TestDecodeTypes(t *testing.T) { "Add custom media type", []map[string]interface{}{ { - "text/hugo": map[string]interface{}{ - "suffix": "hgo"}}}, + "text/hugo+hgo": map[string]interface{}{ + "Suffixes": []string{"hgo2"}}}}, false, func(t *testing.T, name string, tt Types) { require.Len(t, tt, len(DefaultTypes)+1) @@ -188,7 +192,7 @@ func TestDecodeTypes(t *testing.T) { _, found := tt.GetBySuffix("json") require.True(t, found) - hugo, found := tt.GetBySuffix("hgo") + hugo, found := tt.GetBySuffix("hgo2") require.True(t, found) require.Equal(t, "text/hugo+hgo", hugo.String(), name) }}, -- cgit v1.2.3