hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

page_matcher.go (3364B)

    1 // Copyright 2020 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 page
   15 
   16 import (
   17 	"fmt"
   18 	"path/filepath"
   19 	"strings"
   20 
   21 	"github.com/gohugoio/hugo/common/maps"
   22 	"github.com/gohugoio/hugo/hugofs/glob"
   23 	"github.com/mitchellh/mapstructure"
   24 )
   25 
   26 // A PageMatcher can be used to match a Page with Glob patterns.
   27 // Note that the pattern matching is case insensitive.
   28 type PageMatcher struct {
   29 	// A Glob pattern matching the content path below /content.
   30 	// Expects Unix-styled slashes.
   31 	// Note that this is the virtual path, so it starts at the mount root
   32 	// with a leading "/".
   33 	Path string
   34 
   35 	// A Glob pattern matching the Page's Kind(s), e.g. "{home,section}"
   36 	Kind string
   37 
   38 	// A Glob pattern matching the Page's language, e.g. "{en,sv}".
   39 	Lang string
   40 
   41 	// A Glob pattern matching the Page's Environment, e.g. "{production,development}".
   42 	Environment string
   43 }
   44 
   45 // Matches returns whether p matches this matcher.
   46 func (m PageMatcher) Matches(p Page) bool {
   47 	if m.Kind != "" {
   48 		g, err := glob.GetGlob(m.Kind)
   49 		if err == nil && !g.Match(p.Kind()) {
   50 			return false
   51 		}
   52 	}
   53 
   54 	if m.Lang != "" {
   55 		g, err := glob.GetGlob(m.Lang)
   56 		if err == nil && !g.Match(p.Lang()) {
   57 			return false
   58 		}
   59 	}
   60 
   61 	if m.Path != "" {
   62 		g, err := glob.GetGlob(m.Path)
   63 		// TODO(bep) Path() vs filepath vs leading slash.
   64 		p := strings.ToLower(filepath.ToSlash(p.Pathc()))
   65 		if !(strings.HasPrefix(p, "/")) {
   66 			p = "/" + p
   67 		}
   68 		if err == nil && !g.Match(p) {
   69 			return false
   70 		}
   71 	}
   72 
   73 	if m.Environment != "" {
   74 		g, err := glob.GetGlob(m.Environment)
   75 		if err == nil && !g.Match(p.Site().Hugo().Environment) {
   76 			return false
   77 		}
   78 	}
   79 
   80 	return true
   81 }
   82 
   83 // DecodeCascade decodes in which could be either a map or a slice of maps.
   84 func DecodeCascade(in any) (map[PageMatcher]maps.Params, error) {
   85 	m, err := maps.ToSliceStringMap(in)
   86 	if err != nil {
   87 		return map[PageMatcher]maps.Params{
   88 			{}: maps.ToStringMap(in),
   89 		}, nil
   90 	}
   91 
   92 	cascade := make(map[PageMatcher]maps.Params)
   93 
   94 	for _, vv := range m {
   95 		var m PageMatcher
   96 		if mv, found := vv["_target"]; found {
   97 			err := DecodePageMatcher(mv, &m)
   98 			if err != nil {
   99 				return nil, err
  100 			}
  101 		}
  102 		c, found := cascade[m]
  103 		if found {
  104 			// Merge
  105 			for k, v := range vv {
  106 				if _, found := c[k]; !found {
  107 					c[k] = v
  108 				}
  109 			}
  110 		} else {
  111 			cascade[m] = vv
  112 		}
  113 	}
  114 
  115 	return cascade, nil
  116 }
  117 
  118 // DecodePageMatcher decodes m into v.
  119 func DecodePageMatcher(m any, v *PageMatcher) error {
  120 	if err := mapstructure.WeakDecode(m, v); err != nil {
  121 		return err
  122 	}
  123 
  124 	v.Kind = strings.ToLower(v.Kind)
  125 	if v.Kind != "" {
  126 		g, _ := glob.GetGlob(v.Kind)
  127 		found := false
  128 		for _, k := range kindMap {
  129 			if g.Match(k) {
  130 				found = true
  131 				break
  132 			}
  133 		}
  134 		if !found {
  135 			return fmt.Errorf("%q did not match a valid Page Kind", v.Kind)
  136 		}
  137 	}
  138 
  139 	v.Path = filepath.ToSlash(strings.ToLower(v.Path))
  140 
  141 	return nil
  142 }