mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-27 22:09:53 +02:00
tpl/tplimpl: Reimplement the ".Params tolower" template transformer
All `.Params` are stored lowercase, but it should work to access them `.Page.camelCase` etc. There was, however, some holes in the logic with the old transformer. This commit fixes that by applying a blacklist instead of the old whitelist logic. `.Param` is a very distinct key. The original case will be kept in `.Data.Params.myParam`, but other than that it will be lowercased. Fixes #5068
This commit is contained in:
@@ -24,15 +24,14 @@ import (
|
||||
// decl keeps track of the variable mappings, i.e. $mysite => .Site etc.
|
||||
type decl map[string]string
|
||||
|
||||
var paramsPaths = [][]string{
|
||||
{"Params"},
|
||||
{"Site", "Params"},
|
||||
const (
|
||||
paramsIdentifier = "Params"
|
||||
)
|
||||
|
||||
// Site and Pag referenced from shortcodes
|
||||
{"Page", "Site", "Params"},
|
||||
{"Page", "Params"},
|
||||
|
||||
{"Site", "Language", "Params"},
|
||||
// Containers that may contain Params that we will not touch.
|
||||
var reservedContainers = map[string]bool{
|
||||
// Aka .Site.Data.Params which must stay case sensitive.
|
||||
"Data": true,
|
||||
}
|
||||
|
||||
type templateContext struct {
|
||||
@@ -155,6 +154,7 @@ func (c *templateContext) updateIdentsIfNeeded(idents []string) {
|
||||
for i := index; i < len(idents); i++ {
|
||||
idents[i] = strings.ToLower(idents[i])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// indexOfReplacementStart will return the index of where to start doing replacement,
|
||||
@@ -167,31 +167,101 @@ func (d decl) indexOfReplacementStart(idents []string) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
first := idents[0]
|
||||
firstIsVar := first[0] == '$'
|
||||
|
||||
if l == 1 && !firstIsVar {
|
||||
// This can not be a Params.x
|
||||
return -1
|
||||
}
|
||||
|
||||
if !firstIsVar {
|
||||
found := false
|
||||
for _, paramsPath := range paramsPaths {
|
||||
if first == paramsPath[0] {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
if l == 1 {
|
||||
first := idents[0]
|
||||
if first == "" || first == paramsIdentifier || first[0] == '$' {
|
||||
// This can not be a Params.x
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
var lookFurther bool
|
||||
var needsVarExpansion bool
|
||||
for _, ident := range idents {
|
||||
if ident[0] == '$' {
|
||||
lookFurther = true
|
||||
needsVarExpansion = true
|
||||
break
|
||||
} else if ident == paramsIdentifier {
|
||||
lookFurther = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !lookFurther {
|
||||
return -1
|
||||
}
|
||||
|
||||
var resolvedIdents []string
|
||||
|
||||
if !needsVarExpansion {
|
||||
resolvedIdents = idents
|
||||
} else {
|
||||
var ok bool
|
||||
resolvedIdents, ok = d.resolveVariables(idents)
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
var paramFound bool
|
||||
for i, ident := range resolvedIdents {
|
||||
if ident == paramsIdentifier {
|
||||
if i > 0 {
|
||||
container := resolvedIdents[i-1]
|
||||
if reservedContainers[container] {
|
||||
// .Data.Params.someKey
|
||||
return -1
|
||||
}
|
||||
if !d.isKeyword(container) {
|
||||
// where $pages ".Params.toc_hide" "!=" true
|
||||
return -1
|
||||
}
|
||||
}
|
||||
if i < len(resolvedIdents)-1 {
|
||||
next := resolvedIdents[i+1]
|
||||
if !d.isKeyword(next) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
paramFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !paramFound {
|
||||
return -1
|
||||
}
|
||||
|
||||
var paramSeen bool
|
||||
idx := -1
|
||||
for i, ident := range idents {
|
||||
if ident == "" || ident[0] == '$' {
|
||||
continue
|
||||
}
|
||||
|
||||
if ident == paramsIdentifier {
|
||||
paramSeen = true
|
||||
idx = -1
|
||||
|
||||
} else {
|
||||
if paramSeen {
|
||||
return i
|
||||
}
|
||||
if idx == -1 {
|
||||
idx = i
|
||||
}
|
||||
}
|
||||
}
|
||||
return idx
|
||||
|
||||
}
|
||||
|
||||
func (d decl) resolveVariables(idents []string) ([]string, bool) {
|
||||
var (
|
||||
resolvedIdents []string
|
||||
replacements []string
|
||||
replaced []string
|
||||
replacements []string
|
||||
replaced []string
|
||||
)
|
||||
|
||||
// An Ident can start out as one of
|
||||
@@ -206,7 +276,7 @@ func (d decl) indexOfReplacementStart(idents []string) int {
|
||||
|
||||
if i > 20 {
|
||||
// bail out
|
||||
return -1
|
||||
return nil, false
|
||||
}
|
||||
|
||||
potentialVar := replacements[i]
|
||||
@@ -225,7 +295,7 @@ func (d decl) indexOfReplacementStart(idents []string) int {
|
||||
|
||||
if !ok {
|
||||
// Temporary range vars. We do not care about those.
|
||||
return -1
|
||||
return nil, false
|
||||
}
|
||||
|
||||
replacement = strings.TrimPrefix(replacement, ".")
|
||||
@@ -242,52 +312,10 @@ func (d decl) indexOfReplacementStart(idents []string) int {
|
||||
}
|
||||
}
|
||||
|
||||
resolvedIdents = append(replaced, idents[1:]...)
|
||||
|
||||
for _, paramPath := range paramsPaths {
|
||||
if index := indexOfFirstRealIdentAfterWords(resolvedIdents, idents, paramPath...); index != -1 {
|
||||
return index
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
return append(replaced, idents[1:]...), true
|
||||
|
||||
}
|
||||
|
||||
func indexOfFirstRealIdentAfterWords(resolvedIdents, idents []string, words ...string) int {
|
||||
if !sliceStartsWith(resolvedIdents, words...) {
|
||||
return -1
|
||||
}
|
||||
|
||||
for i, ident := range idents {
|
||||
if ident == "" || ident[0] == '$' {
|
||||
continue
|
||||
}
|
||||
found := true
|
||||
for _, word := range words {
|
||||
if ident == word {
|
||||
found = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if found {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func sliceStartsWith(slice []string, words ...string) bool {
|
||||
|
||||
if len(slice) < len(words) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, word := range words {
|
||||
if word != slice[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
func (d decl) isKeyword(s string) bool {
|
||||
return !strings.ContainsAny(s, " -\"")
|
||||
}
|
||||
|
Reference in New Issue
Block a user