templatedescriptor.go - hugo - [fork] hugo port for 9front
 (HTM) git clone https://git.drkhsh.at/hugo.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
       templatedescriptor.go (7437B)
       ---
            1 // Copyright 2025 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 tplimpl
           15 
           16 import (
           17         "github.com/gohugoio/hugo/resources/kinds"
           18 )
           19 
           20 const baseNameBaseof = "baseof"
           21 
           22 // This is used both as a key and in lookups.
           23 type TemplateDescriptor struct {
           24         // Group 1.
           25         Kind               string // page, home, section, taxonomy, term (and only those)
           26         LayoutFromTemplate string // list, single, all,mycustomlayout
           27         LayoutFromUser     string //  custom layout set in front matter, e.g. list, single, all, mycustomlayout
           28 
           29         // Group 2.
           30         OutputFormat string // rss, csv ...
           31         MediaType    string // text/html, text/plain, ...
           32         Lang         string // en, nn, fr, ...
           33 
           34         Variant1 string // contextual variant, e.g. "link" in render hooks."
           35         Variant2 string // contextual variant, e.g. "id" in render.
           36 
           37         // Misc.
           38         LayoutFromUserMustMatch bool // If set, we only look for the exact layout.
           39         IsPlainText             bool // Whether this is a plain text template.
           40         AlwaysAllowPlainText    bool // Whether to e.g. allow plain text templates to be rendered in HTML.
           41 }
           42 
           43 func (d *TemplateDescriptor) normalizeFromFile() {
           44         if d.LayoutFromTemplate == d.OutputFormat {
           45                 d.LayoutFromTemplate = ""
           46         }
           47 
           48         if d.Kind == kinds.KindTemporary {
           49                 d.Kind = ""
           50         }
           51 
           52         if d.LayoutFromTemplate == d.Kind {
           53                 d.LayoutFromTemplate = ""
           54         }
           55 }
           56 
           57 type descriptorHandler struct {
           58         opts StoreOptions
           59 }
           60 
           61 // Note that this in this setup is usually a descriptor constructed from a page,
           62 // so we want to find the best match for that page.
           63 func (s descriptorHandler) compareDescriptors(category Category, isEmbedded bool, this, other TemplateDescriptor) weight {
           64         if this.LayoutFromUserMustMatch && this.LayoutFromUser != other.LayoutFromTemplate {
           65                 return weightNoMatch
           66         }
           67 
           68         w := this.doCompare(category, s.opts.DefaultContentLanguage, other)
           69 
           70         if w.w1 <= 0 {
           71                 if category == CategoryMarkup && (this.Variant1 == other.Variant1) && (this.Variant2 == other.Variant2 || this.Variant2 != "" && other.Variant2 == "") {
           72                         // See issue 13242.
           73                         if this.OutputFormat != other.OutputFormat && this.OutputFormat == s.opts.DefaultOutputFormat {
           74                                 return w
           75                         }
           76 
           77                         w.w1 = 1
           78                 }
           79 
           80                 if category == CategoryShortcode {
           81                         if (this.IsPlainText == other.IsPlainText || !other.IsPlainText) || this.AlwaysAllowPlainText {
           82                                 w.w1 = 1
           83                         }
           84                 }
           85         }
           86 
           87         return w
           88 }
           89 
           90 //lint:ignore ST1006 this vs other makes it easier to reason about.
           91 func (this TemplateDescriptor) doCompare(category Category, defaultContentLanguage string, other TemplateDescriptor) weight {
           92         w := weightNoMatch
           93 
           94         if !this.AlwaysAllowPlainText {
           95                 // HTML in plain text is OK, but not the other way around.
           96                 if other.IsPlainText && !this.IsPlainText {
           97                         return w
           98                 }
           99         }
          100 
          101         if other.Kind != "" && other.Kind != this.Kind {
          102                 return w
          103         }
          104 
          105         if other.LayoutFromTemplate != "" && other.LayoutFromTemplate != layoutAll {
          106                 if this.LayoutFromUser == "" || this.LayoutFromUser != other.LayoutFromTemplate {
          107                         if other.LayoutFromTemplate != this.LayoutFromTemplate {
          108                                 return w
          109                         }
          110                 }
          111         }
          112 
          113         if other.Lang != "" && other.Lang != this.Lang {
          114                 return w
          115         }
          116 
          117         if other.OutputFormat != "" && other.OutputFormat != this.OutputFormat {
          118                 if this.MediaType != other.MediaType {
          119                         return w
          120                 }
          121 
          122                 // We want e.g. home page in amp output format (media type text/html) to
          123                 // find a template even if one isn't specified for that output format,
          124                 // when one exist for the html output format (same media type).
          125                 skip := category != CategoryBaseof && (this.Kind == "" || (this.Kind != other.Kind && (this.LayoutFromTemplate != other.LayoutFromTemplate && other.LayoutFromTemplate != layoutAll)))
          126                 if this.LayoutFromUser != "" {
          127                         skip = skip && (this.LayoutFromUser != other.LayoutFromTemplate)
          128                 }
          129                 if skip {
          130                         return w
          131                 }
          132 
          133                 // Continue.
          134         }
          135 
          136         if other.MediaType != this.MediaType {
          137                 return w
          138         }
          139 
          140         // One example of variant1 and 2 is for render codeblocks:
          141         // variant1=codeblock, variant2=go (language).
          142         if other.Variant1 != "" {
          143                 if other.Variant1 != this.Variant1 {
          144                         return w
          145                 }
          146 
          147                 if other.Variant2 != "" && other.Variant2 != this.Variant2 {
          148                         return w
          149                 }
          150         }
          151 
          152         const (
          153                 weightKind           = 5 // page, home, section, taxonomy, term (and only those)
          154                 weightcustomLayout   = 6 // custom layout (mylayout, set in e.g. front matter)
          155                 weightLayoutStandard = 4 // standard layouts (single,list)
          156                 weightLayoutAll      = 2 // the "all" layout
          157                 weightOutputFormat   = 4 // a configured output format (e.g. rss, html, json)
          158                 weightMediaType      = 1 // a configured media type (e.g. text/html, text/plain)
          159                 weightLang           = 1 // a configured language (e.g. en, nn, fr, ...)
          160                 weightVariant1       = 6 // currently used for render hooks, e.g. "link", "image"
          161                 weightVariant2       = 4 // currently used for render hooks, e.g. the language "go" in code blocks.
          162 
          163                 // We will use the values for group 2 and 3
          164                 // if the distance up to the template is shorter than
          165                 // the one we're comparing with.
          166                 // E.g for a page in /posts/mypage.md with the
          167                 // two templates /layouts/posts/single.html and /layouts/page.html,
          168                 // the first one is the best match even if the second one
          169                 // has a higher w1 value.
          170                 weight2Group1 = 1 // kind, standardl layout (single,list,all)
          171                 weight2Group2 = 2 // custom layout (mylayout)
          172 
          173                 weight3 = 1 // for media type, lang, output format.
          174         )
          175 
          176         // Now we now know that the other descriptor is a subset of this.
          177         // Now calculate the weights.
          178         w.w1++
          179 
          180         if other.Kind != "" && other.Kind == this.Kind {
          181                 w.w1 += weightKind
          182                 w.w2 = weight2Group1
          183         }
          184 
          185         if other.LayoutFromTemplate != "" && (other.LayoutFromTemplate == this.LayoutFromTemplate) {
          186                 w.w1 += weightLayoutStandard
          187                 w.w2 = weight2Group1
          188         } else if other.LayoutFromTemplate == layoutAll {
          189                 w.w1 += weightLayoutAll
          190                 w.w2 = weight2Group1
          191         }
          192 
          193         // LayoutCustom is only set in this (usually from Page.Layout).
          194         if this.LayoutFromUser != "" && this.LayoutFromUser == other.LayoutFromTemplate {
          195                 w.w1 += weightcustomLayout
          196                 w.w2 = weight2Group2
          197         }
          198 
          199         if (other.Lang != "" && other.Lang == this.Lang) || (other.Lang == "" && this.Lang == defaultContentLanguage) {
          200                 w.w1 += weightLang
          201                 w.w3 += weight3
          202         }
          203 
          204         if other.OutputFormat != "" && other.OutputFormat == this.OutputFormat {
          205                 w.w1 += weightOutputFormat
          206                 w.w3 += weight3
          207         }
          208 
          209         if other.MediaType != "" && other.MediaType == this.MediaType {
          210                 w.w1 += weightMediaType
          211                 w.w3 += weight3
          212         }
          213 
          214         if other.Variant1 != "" && other.Variant1 == this.Variant1 {
          215                 w.w1 += weightVariant1
          216         }
          217 
          218         if other.Variant1 != "" && other.Variant2 == this.Variant2 {
          219                 w.w1 += weightVariant2
          220         }
          221 
          222         return w
          223 }
          224 
          225 func (d TemplateDescriptor) IsZero() bool {
          226         return d == TemplateDescriptor{}
          227 }
          228 
          229 //lint:ignore ST1006 this vs other makes it easier to reason about.
          230 func (this TemplateDescriptor) isKindInLayout(layout string) bool {
          231         if this.Kind == "" {
          232                 return true
          233         }
          234         if this.Kind != kinds.KindPage {
          235                 return layout != layoutSingle
          236         }
          237         return layout != layoutList
          238 }