github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/config/allconfig/alldecoders.go (about)

     1  // Copyright 2023 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package allconfig
    15  
    16  import (
    17  	"fmt"
    18  	"strings"
    19  
    20  	"github.com/gohugoio/hugo/cache/filecache"
    21  	"github.com/gohugoio/hugo/common/maps"
    22  	"github.com/gohugoio/hugo/common/types"
    23  	"github.com/gohugoio/hugo/config"
    24  	"github.com/gohugoio/hugo/config/privacy"
    25  	"github.com/gohugoio/hugo/config/security"
    26  	"github.com/gohugoio/hugo/config/services"
    27  	"github.com/gohugoio/hugo/deploy"
    28  	"github.com/gohugoio/hugo/langs"
    29  	"github.com/gohugoio/hugo/markup/markup_config"
    30  	"github.com/gohugoio/hugo/media"
    31  	"github.com/gohugoio/hugo/minifiers"
    32  	"github.com/gohugoio/hugo/modules"
    33  	"github.com/gohugoio/hugo/navigation"
    34  	"github.com/gohugoio/hugo/output"
    35  	"github.com/gohugoio/hugo/related"
    36  	"github.com/gohugoio/hugo/resources/images"
    37  	"github.com/gohugoio/hugo/resources/page"
    38  	"github.com/gohugoio/hugo/resources/page/pagemeta"
    39  	"github.com/mitchellh/mapstructure"
    40  	"github.com/spf13/afero"
    41  	"github.com/spf13/cast"
    42  )
    43  
    44  type decodeConfig struct {
    45  	p    config.Provider
    46  	c    *Config
    47  	fs   afero.Fs
    48  	bcfg config.BaseConfig
    49  }
    50  
    51  type decodeWeight struct {
    52  	key                  string
    53  	decode               func(decodeWeight, decodeConfig) error
    54  	getCompiler          func(c *Config) configCompiler
    55  	weight               int
    56  	internalOrDeprecated bool // Hide it from the docs.
    57  }
    58  
    59  var allDecoderSetups = map[string]decodeWeight{
    60  	"": {
    61  		key:    "",
    62  		weight: -100, // Always first.
    63  		decode: func(d decodeWeight, p decodeConfig) error {
    64  			if err := mapstructure.WeakDecode(p.p.Get(""), &p.c.RootConfig); err != nil {
    65  				return err
    66  			}
    67  
    68  			// This need to match with Lang which is always lower case.
    69  			p.c.RootConfig.DefaultContentLanguage = strings.ToLower(p.c.RootConfig.DefaultContentLanguage)
    70  
    71  			return nil
    72  		},
    73  	},
    74  	"imaging": {
    75  		key: "imaging",
    76  		decode: func(d decodeWeight, p decodeConfig) error {
    77  			var err error
    78  			p.c.Imaging, err = images.DecodeConfig(p.p.GetStringMap(d.key))
    79  			return err
    80  		},
    81  	},
    82  	"caches": {
    83  		key: "caches",
    84  		decode: func(d decodeWeight, p decodeConfig) error {
    85  			var err error
    86  			p.c.Caches, err = filecache.DecodeConfig(p.fs, p.bcfg, p.p.GetStringMap(d.key))
    87  			if p.c.IgnoreCache {
    88  				// Set MaxAge in all caches to 0.
    89  				for k, cache := range p.c.Caches {
    90  					cache.MaxAge = 0
    91  					p.c.Caches[k] = cache
    92  				}
    93  			}
    94  			return err
    95  		},
    96  	},
    97  	"build": {
    98  		key: "build",
    99  		decode: func(d decodeWeight, p decodeConfig) error {
   100  			p.c.Build = config.DecodeBuildConfig(p.p)
   101  			return nil
   102  		},
   103  		getCompiler: func(c *Config) configCompiler {
   104  			return &c.Build
   105  		},
   106  	},
   107  	"frontmatter": {
   108  		key: "frontmatter",
   109  		decode: func(d decodeWeight, p decodeConfig) error {
   110  			var err error
   111  			p.c.Frontmatter, err = pagemeta.DecodeFrontMatterConfig(p.p)
   112  			return err
   113  		},
   114  	},
   115  	"markup": {
   116  		key: "markup",
   117  		decode: func(d decodeWeight, p decodeConfig) error {
   118  			var err error
   119  			p.c.Markup, err = markup_config.Decode(p.p)
   120  			return err
   121  		},
   122  	},
   123  	"server": {
   124  		key: "server",
   125  		decode: func(d decodeWeight, p decodeConfig) error {
   126  			var err error
   127  			p.c.Server, err = config.DecodeServer(p.p)
   128  			return err
   129  		},
   130  		getCompiler: func(c *Config) configCompiler {
   131  			return &c.Server
   132  		},
   133  	},
   134  	"minify": {
   135  		key: "minify",
   136  		decode: func(d decodeWeight, p decodeConfig) error {
   137  			var err error
   138  			p.c.Minify, err = minifiers.DecodeConfig(p.p.Get(d.key))
   139  			return err
   140  		},
   141  	},
   142  	"mediatypes": {
   143  		key: "mediatypes",
   144  		decode: func(d decodeWeight, p decodeConfig) error {
   145  			var err error
   146  			p.c.MediaTypes, err = media.DecodeTypes(p.p.GetStringMap(d.key))
   147  			return err
   148  		},
   149  	},
   150  	"outputs": {
   151  		key: "outputs",
   152  		decode: func(d decodeWeight, p decodeConfig) error {
   153  			defaults := createDefaultOutputFormats(p.c.OutputFormats.Config)
   154  			m := maps.CleanConfigStringMap(p.p.GetStringMap("outputs"))
   155  			p.c.Outputs = make(map[string][]string)
   156  			for k, v := range m {
   157  				s := types.ToStringSlicePreserveString(v)
   158  				for i, v := range s {
   159  					s[i] = strings.ToLower(v)
   160  				}
   161  				p.c.Outputs[k] = s
   162  			}
   163  			// Apply defaults.
   164  			for k, v := range defaults {
   165  				if _, found := p.c.Outputs[k]; !found {
   166  					p.c.Outputs[k] = v
   167  				}
   168  			}
   169  			return nil
   170  		},
   171  	},
   172  	"outputformats": {
   173  		key: "outputformats",
   174  		decode: func(d decodeWeight, p decodeConfig) error {
   175  			var err error
   176  			p.c.OutputFormats, err = output.DecodeConfig(p.c.MediaTypes.Config, p.p.Get(d.key))
   177  			return err
   178  		},
   179  	},
   180  	"params": {
   181  		key: "params",
   182  		decode: func(d decodeWeight, p decodeConfig) error {
   183  			p.c.Params = maps.CleanConfigStringMap(p.p.GetStringMap("params"))
   184  			if p.c.Params == nil {
   185  				p.c.Params = make(map[string]any)
   186  			}
   187  
   188  			// Before Hugo 0.112.0 this was configured via site Params.
   189  			if mainSections, found := p.c.Params["mainsections"]; found {
   190  				p.c.MainSections = types.ToStringSlicePreserveString(mainSections)
   191  				if p.c.MainSections == nil {
   192  					p.c.MainSections = []string{}
   193  				}
   194  			}
   195  
   196  			return nil
   197  		},
   198  	},
   199  	"module": {
   200  		key: "module",
   201  		decode: func(d decodeWeight, p decodeConfig) error {
   202  			var err error
   203  			p.c.Module, err = modules.DecodeConfig(p.p)
   204  			return err
   205  		},
   206  	},
   207  	"permalinks": {
   208  		key: "permalinks",
   209  		decode: func(d decodeWeight, p decodeConfig) error {
   210  			var err error
   211  			p.c.Permalinks, err = page.DecodePermalinksConfig(p.p.GetStringMap(d.key))
   212  			return err
   213  		},
   214  	},
   215  	"sitemap": {
   216  		key: "sitemap",
   217  		decode: func(d decodeWeight, p decodeConfig) error {
   218  			var err error
   219  			p.c.Sitemap, err = config.DecodeSitemap(config.SitemapConfig{Priority: -1, Filename: "sitemap.xml"}, p.p.GetStringMap(d.key))
   220  			return err
   221  		},
   222  	},
   223  	"taxonomies": {
   224  		key: "taxonomies",
   225  		decode: func(d decodeWeight, p decodeConfig) error {
   226  			p.c.Taxonomies = maps.CleanConfigStringMapString(p.p.GetStringMapString(d.key))
   227  			return nil
   228  		},
   229  	},
   230  	"related": {
   231  		key:    "related",
   232  		weight: 100, // This needs to be decoded after taxonomies.
   233  		decode: func(d decodeWeight, p decodeConfig) error {
   234  			if p.p.IsSet(d.key) {
   235  				var err error
   236  				p.c.Related, err = related.DecodeConfig(p.p.GetParams(d.key))
   237  				if err != nil {
   238  					return fmt.Errorf("failed to decode related config: %w", err)
   239  				}
   240  			} else {
   241  				p.c.Related = related.DefaultConfig
   242  				if _, found := p.c.Taxonomies["tag"]; found {
   243  					p.c.Related.Add(related.IndexConfig{Name: "tags", Weight: 80, Type: related.TypeBasic})
   244  				}
   245  			}
   246  			return nil
   247  		},
   248  	},
   249  	"languages": {
   250  		key: "languages",
   251  		decode: func(d decodeWeight, p decodeConfig) error {
   252  			var err error
   253  			m := p.p.GetStringMap(d.key)
   254  			if len(m) == 1 {
   255  				// In v0.112.4 we moved this to the language config, but it's very commmon for mono language sites to have this at the top level.
   256  				var first maps.Params
   257  				var ok bool
   258  				for _, v := range m {
   259  					first, ok = v.(maps.Params)
   260  					if ok {
   261  						break
   262  					}
   263  				}
   264  				if first != nil {
   265  					if _, found := first["languagecode"]; !found {
   266  						first["languagecode"] = p.p.GetString("languagecode")
   267  					}
   268  				}
   269  			}
   270  			p.c.Languages, err = langs.DecodeConfig(m)
   271  			if err != nil {
   272  				return err
   273  			}
   274  
   275  			// Validate defaultContentLanguage.
   276  			var found bool
   277  			for lang := range p.c.Languages {
   278  				if lang == p.c.DefaultContentLanguage {
   279  					found = true
   280  					break
   281  				}
   282  			}
   283  			if !found {
   284  				return fmt.Errorf("config value %q for defaultContentLanguage does not match any language definition", p.c.DefaultContentLanguage)
   285  			}
   286  
   287  			return nil
   288  		},
   289  	},
   290  	"cascade": {
   291  		key: "cascade",
   292  		decode: func(d decodeWeight, p decodeConfig) error {
   293  			var err error
   294  			p.c.Cascade, err = page.DecodeCascadeConfig(p.p.Get(d.key))
   295  			return err
   296  		},
   297  	},
   298  	"menus": {
   299  		key: "menus",
   300  		decode: func(d decodeWeight, p decodeConfig) error {
   301  			var err error
   302  			p.c.Menus, err = navigation.DecodeConfig(p.p.Get(d.key))
   303  			return err
   304  		},
   305  	},
   306  	"privacy": {
   307  		key: "privacy",
   308  		decode: func(d decodeWeight, p decodeConfig) error {
   309  			var err error
   310  			p.c.Privacy, err = privacy.DecodeConfig(p.p)
   311  			return err
   312  		},
   313  	},
   314  	"security": {
   315  		key: "security",
   316  		decode: func(d decodeWeight, p decodeConfig) error {
   317  			var err error
   318  			p.c.Security, err = security.DecodeConfig(p.p)
   319  			return err
   320  		},
   321  	},
   322  	"services": {
   323  		key: "services",
   324  		decode: func(d decodeWeight, p decodeConfig) error {
   325  			var err error
   326  			p.c.Services, err = services.DecodeConfig(p.p)
   327  			return err
   328  		},
   329  	},
   330  	"deployment": {
   331  		key: "deployment",
   332  		decode: func(d decodeWeight, p decodeConfig) error {
   333  			var err error
   334  			p.c.Deployment, err = deploy.DecodeConfig(p.p)
   335  			return err
   336  		},
   337  	},
   338  	"author": {
   339  		key: "author",
   340  		decode: func(d decodeWeight, p decodeConfig) error {
   341  			p.c.Author = maps.CleanConfigStringMap(p.p.GetStringMap(d.key))
   342  			return nil
   343  		},
   344  		internalOrDeprecated: true,
   345  	},
   346  	"social": {
   347  		key: "social",
   348  		decode: func(d decodeWeight, p decodeConfig) error {
   349  			p.c.Social = maps.CleanConfigStringMapString(p.p.GetStringMapString(d.key))
   350  			return nil
   351  		},
   352  		internalOrDeprecated: true,
   353  	},
   354  	"uglyurls": {
   355  		key: "uglyurls",
   356  		decode: func(d decodeWeight, p decodeConfig) error {
   357  			v := p.p.Get(d.key)
   358  			switch vv := v.(type) {
   359  			case bool:
   360  				p.c.UglyURLs = vv
   361  			case string:
   362  				p.c.UglyURLs = vv == "true"
   363  			default:
   364  				p.c.UglyURLs = cast.ToStringMapBool(v)
   365  			}
   366  			return nil
   367  		},
   368  		internalOrDeprecated: true,
   369  	},
   370  	"internal": {
   371  		key: "internal",
   372  		decode: func(d decodeWeight, p decodeConfig) error {
   373  			return mapstructure.WeakDecode(p.p.GetStringMap(d.key), &p.c.Internal)
   374  		},
   375  		internalOrDeprecated: true,
   376  	},
   377  }
   378  
   379  func init() {
   380  	for k, v := range allDecoderSetups {
   381  		// Verify that k and v.key is all lower case.
   382  		if k != strings.ToLower(k) {
   383  			panic(fmt.Sprintf("key %q is not lower case", k))
   384  		}
   385  		if v.key != strings.ToLower(v.key) {
   386  			panic(fmt.Sprintf("key %q is not lower case", v.key))
   387  		}
   388  
   389  		if k != v.key {
   390  			panic(fmt.Sprintf("key %q is not the same as the map key %q", k, v.key))
   391  		}
   392  	}
   393  }