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:
Bjørn Erik Pedersen
2023-01-04 18:24:36 +01:00
parent 6aededf6b4
commit 241b21b0fd
337 changed files with 13377 additions and 14898 deletions

View File

@@ -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

View File

@@ -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{})
}

View File

@@ -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 {

View File

@@ -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{