mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-28 22:19:59 +02:00
Create a struct with all of Hugo's config options
Primary motivation is documentation, but it will also hopefully simplify the code. Also, * Lower case the default output format names; this is in line with the custom ones (map keys) and how it's treated all the places. This avoids doing `stringds.EqualFold` everywhere. Closes #10896 Closes #10620
This commit is contained in:
@@ -43,25 +43,25 @@ func ToStringMapE(in any) (map[string]any, error) {
|
||||
// ToParamsAndPrepare converts in to Params and prepares it for use.
|
||||
// If in is nil, an empty map is returned.
|
||||
// See PrepareParams.
|
||||
func ToParamsAndPrepare(in any) (Params, bool) {
|
||||
func ToParamsAndPrepare(in any) (Params, error) {
|
||||
if types.IsNil(in) {
|
||||
return Params{}, true
|
||||
return Params{}, nil
|
||||
}
|
||||
m, err := ToStringMapE(in)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
return nil, err
|
||||
}
|
||||
PrepareParams(m)
|
||||
return m, true
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// MustToParamsAndPrepare calls ToParamsAndPrepare and panics if it fails.
|
||||
func MustToParamsAndPrepare(in any) Params {
|
||||
if p, ok := ToParamsAndPrepare(in); ok {
|
||||
return p
|
||||
} else {
|
||||
panic(fmt.Sprintf("cannot convert %T to maps.Params", in))
|
||||
p, err := ToParamsAndPrepare(in)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("cannot convert %T to maps.Params: %s", in, err))
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// ToStringMap converts in to map[string]interface{}.
|
||||
@@ -96,6 +96,8 @@ func ToSliceStringMap(in any) ([]map[string]any, error) {
|
||||
switch v := in.(type) {
|
||||
case []map[string]any:
|
||||
return v, nil
|
||||
case Params:
|
||||
return []map[string]any{v}, nil
|
||||
case []any:
|
||||
var s []map[string]any
|
||||
for _, entry := range v {
|
||||
@@ -123,6 +125,23 @@ func LookupEqualFold[T any | string](m map[string]T, key string) (T, bool) {
|
||||
return s, false
|
||||
}
|
||||
|
||||
// MergeShallow merges src into dst, but only if the key does not already exist in dst.
|
||||
// The keys are compared case insensitively.
|
||||
func MergeShallow(dst, src map[string]any) {
|
||||
for k, v := range src {
|
||||
found := false
|
||||
for dk := range dst {
|
||||
if strings.EqualFold(dk, k) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
dst[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type keyRename struct {
|
||||
pattern glob.Glob
|
||||
newKey string
|
||||
|
@@ -116,11 +116,11 @@ func TestToSliceStringMap(t *testing.T) {
|
||||
|
||||
func TestToParamsAndPrepare(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
_, ok := ToParamsAndPrepare(map[string]any{"A": "av"})
|
||||
c.Assert(ok, qt.IsTrue)
|
||||
_, err := ToParamsAndPrepare(map[string]any{"A": "av"})
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
params, ok := ToParamsAndPrepare(nil)
|
||||
c.Assert(ok, qt.IsTrue)
|
||||
params, err := ToParamsAndPrepare(nil)
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(params, qt.DeepEquals, Params{})
|
||||
}
|
||||
|
||||
|
@@ -23,30 +23,37 @@ import (
|
||||
// Params is a map where all keys are lower case.
|
||||
type Params map[string]any
|
||||
|
||||
// Get does a lower case and nested search in this map.
|
||||
// KeyParams is an utility struct for the WalkParams method.
|
||||
type KeyParams struct {
|
||||
Key string
|
||||
Params Params
|
||||
}
|
||||
|
||||
// GetNested does a lower case and nested search in this map.
|
||||
// It will return nil if none found.
|
||||
func (p Params) Get(indices ...string) any {
|
||||
// Make all of these methods internal somehow.
|
||||
func (p Params) GetNested(indices ...string) any {
|
||||
v, _, _ := getNested(p, indices)
|
||||
return v
|
||||
}
|
||||
|
||||
// Set overwrites values in p with values in pp for common or new keys.
|
||||
// Set overwrites values in dst with values in src for common or new keys.
|
||||
// This is done recursively.
|
||||
func (p Params) Set(pp Params) {
|
||||
for k, v := range pp {
|
||||
vv, found := p[k]
|
||||
func SetParams(dst, src Params) {
|
||||
for k, v := range src {
|
||||
vv, found := dst[k]
|
||||
if !found {
|
||||
p[k] = v
|
||||
dst[k] = v
|
||||
} else {
|
||||
switch vvv := vv.(type) {
|
||||
case Params:
|
||||
if pv, ok := v.(Params); ok {
|
||||
vvv.Set(pv)
|
||||
SetParams(vvv, pv)
|
||||
} else {
|
||||
p[k] = v
|
||||
dst[k] = v
|
||||
}
|
||||
default:
|
||||
p[k] = v
|
||||
dst[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,18 +77,17 @@ func (p Params) IsZero() bool {
|
||||
|
||||
}
|
||||
|
||||
// Merge transfers values from pp to p for new keys.
|
||||
// MergeParamsWithStrategy transfers values from src to dst for new keys using the merge strategy given.
|
||||
// This is done recursively.
|
||||
func (p Params) Merge(pp Params) {
|
||||
p.merge("", pp)
|
||||
func MergeParamsWithStrategy(strategy string, dst, src Params) {
|
||||
dst.merge(ParamsMergeStrategy(strategy), src)
|
||||
}
|
||||
|
||||
// MergeRoot transfers values from pp to p for new keys where p is the
|
||||
// root of the tree.
|
||||
// MergeParamsWithStrategy transfers values from src to dst for new keys using the merge encoded in dst.
|
||||
// This is done recursively.
|
||||
func (p Params) MergeRoot(pp Params) {
|
||||
ms, _ := p.GetMergeStrategy()
|
||||
p.merge(ms, pp)
|
||||
func MergeParams(dst, src Params) {
|
||||
ms, _ := dst.GetMergeStrategy()
|
||||
dst.merge(ms, src)
|
||||
}
|
||||
|
||||
func (p Params) merge(ps ParamsMergeStrategy, pp Params) {
|
||||
@@ -116,6 +122,7 @@ func (p Params) merge(ps ParamsMergeStrategy, pp Params) {
|
||||
}
|
||||
}
|
||||
|
||||
// For internal use.
|
||||
func (p Params) GetMergeStrategy() (ParamsMergeStrategy, bool) {
|
||||
if v, found := p[mergeStrategyKey]; found {
|
||||
if s, ok := v.(ParamsMergeStrategy); ok {
|
||||
@@ -125,6 +132,7 @@ func (p Params) GetMergeStrategy() (ParamsMergeStrategy, bool) {
|
||||
return ParamsMergeStrategyShallow, false
|
||||
}
|
||||
|
||||
// For internal use.
|
||||
func (p Params) DeleteMergeStrategy() bool {
|
||||
if _, found := p[mergeStrategyKey]; found {
|
||||
delete(p, mergeStrategyKey)
|
||||
@@ -133,7 +141,8 @@ func (p Params) DeleteMergeStrategy() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p Params) SetDefaultMergeStrategy(s ParamsMergeStrategy) {
|
||||
// For internal use.
|
||||
func (p Params) SetMergeStrategy(s ParamsMergeStrategy) {
|
||||
switch s {
|
||||
case ParamsMergeStrategyDeep, ParamsMergeStrategyNone, ParamsMergeStrategyShallow:
|
||||
default:
|
||||
@@ -187,7 +196,7 @@ func GetNestedParam(keyStr, separator string, candidates ...Params) (any, error)
|
||||
|
||||
keySegments := strings.Split(keyStr, separator)
|
||||
for _, m := range candidates {
|
||||
if v := m.Get(keySegments...); v != nil {
|
||||
if v := m.GetNested(keySegments...); v != nil {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
@@ -236,6 +245,55 @@ const (
|
||||
mergeStrategyKey = "_merge"
|
||||
)
|
||||
|
||||
// CleanConfigStringMapString removes any processing instructions from m,
|
||||
// m will never be modified.
|
||||
func CleanConfigStringMapString(m map[string]string) map[string]string {
|
||||
if m == nil || len(m) == 0 {
|
||||
return m
|
||||
}
|
||||
if _, found := m[mergeStrategyKey]; !found {
|
||||
return m
|
||||
}
|
||||
// Create a new map and copy all the keys except the merge strategy key.
|
||||
m2 := make(map[string]string, len(m)-1)
|
||||
for k, v := range m {
|
||||
if k != mergeStrategyKey {
|
||||
m2[k] = v
|
||||
}
|
||||
}
|
||||
return m2
|
||||
}
|
||||
|
||||
// CleanConfigStringMap is the same as CleanConfigStringMapString but for
|
||||
// map[string]any.
|
||||
func CleanConfigStringMap(m map[string]any) map[string]any {
|
||||
if m == nil || len(m) == 0 {
|
||||
return m
|
||||
}
|
||||
if _, found := m[mergeStrategyKey]; !found {
|
||||
return m
|
||||
}
|
||||
// Create a new map and copy all the keys except the merge strategy key.
|
||||
m2 := make(map[string]any, len(m)-1)
|
||||
for k, v := range m {
|
||||
if k != mergeStrategyKey {
|
||||
m2[k] = v
|
||||
}
|
||||
switch v2 := v.(type) {
|
||||
case map[string]any:
|
||||
m2[k] = CleanConfigStringMap(v2)
|
||||
case Params:
|
||||
var p Params = CleanConfigStringMap(v2)
|
||||
m2[k] = p
|
||||
case map[string]string:
|
||||
m2[k] = CleanConfigStringMapString(v2)
|
||||
}
|
||||
|
||||
}
|
||||
return m2
|
||||
|
||||
}
|
||||
|
||||
func toMergeStrategy(v any) ParamsMergeStrategy {
|
||||
s := ParamsMergeStrategy(cast.ToString(v))
|
||||
switch s {
|
||||
|
@@ -81,7 +81,7 @@ func TestParamsSetAndMerge(t *testing.T) {
|
||||
|
||||
p1, p2 := createParamsPair()
|
||||
|
||||
p1.Set(p2)
|
||||
SetParams(p1, p2)
|
||||
|
||||
c.Assert(p1, qt.DeepEquals, Params{
|
||||
"a": "abv",
|
||||
@@ -97,7 +97,7 @@ func TestParamsSetAndMerge(t *testing.T) {
|
||||
|
||||
p1, p2 = createParamsPair()
|
||||
|
||||
p1.Merge(p2)
|
||||
MergeParamsWithStrategy("", p1, p2)
|
||||
|
||||
// Default is to do a shallow merge.
|
||||
c.Assert(p1, qt.DeepEquals, Params{
|
||||
@@ -111,8 +111,8 @@ func TestParamsSetAndMerge(t *testing.T) {
|
||||
})
|
||||
|
||||
p1, p2 = createParamsPair()
|
||||
p1.SetDefaultMergeStrategy(ParamsMergeStrategyNone)
|
||||
p1.Merge(p2)
|
||||
p1.SetMergeStrategy(ParamsMergeStrategyNone)
|
||||
MergeParamsWithStrategy("", p1, p2)
|
||||
p1.DeleteMergeStrategy()
|
||||
|
||||
c.Assert(p1, qt.DeepEquals, Params{
|
||||
@@ -125,8 +125,8 @@ func TestParamsSetAndMerge(t *testing.T) {
|
||||
})
|
||||
|
||||
p1, p2 = createParamsPair()
|
||||
p1.SetDefaultMergeStrategy(ParamsMergeStrategyShallow)
|
||||
p1.Merge(p2)
|
||||
p1.SetMergeStrategy(ParamsMergeStrategyShallow)
|
||||
MergeParamsWithStrategy("", p1, p2)
|
||||
p1.DeleteMergeStrategy()
|
||||
|
||||
c.Assert(p1, qt.DeepEquals, Params{
|
||||
@@ -140,8 +140,8 @@ func TestParamsSetAndMerge(t *testing.T) {
|
||||
})
|
||||
|
||||
p1, p2 = createParamsPair()
|
||||
p1.SetDefaultMergeStrategy(ParamsMergeStrategyDeep)
|
||||
p1.Merge(p2)
|
||||
p1.SetMergeStrategy(ParamsMergeStrategyDeep)
|
||||
MergeParamsWithStrategy("", p1, p2)
|
||||
p1.DeleteMergeStrategy()
|
||||
|
||||
c.Assert(p1, qt.DeepEquals, Params{
|
||||
|
Reference in New Issue
Block a user