URI: 
       outputFormat.go - hugo - [fork] hugo port for 9front
  HTML git clone https://git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
       outputFormat.go (9610B)
       ---
            1 // Copyright 2019 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 output contains Output Format types and functions.
           15 package output
           16 
           17 import (
           18         "encoding/json"
           19         "fmt"
           20         "sort"
           21         "strings"
           22 
           23         "github.com/gohugoio/hugo/media"
           24 )
           25 
           26 // Format represents an output representation, usually to a file on disk.
           27 // <docsmeta>{ "name": "OutputFormat" }</docsmeta>
           28 type Format struct {
           29         // The Name is used as an identifier. Internal output formats (i.e. html and rss)
           30         // can be overridden by providing a new definition for those types.
           31         // <docsmeta>{ "identifiers": ["html", "rss"] }</docsmeta>
           32         Name string `json:"-"`
           33 
           34         MediaType media.Type `json:"-"`
           35 
           36         // Must be set to a value when there are two or more conflicting mediatype for the same resource.
           37         Path string `json:"path"`
           38 
           39         // The base output file name used when not using "ugly URLs", defaults to "index".
           40         BaseName string `json:"baseName"`
           41 
           42         // The value to use for rel links.
           43         Rel string `json:"rel"`
           44 
           45         // The protocol to use, i.e. "webcal://". Defaults to the protocol of the baseURL.
           46         Protocol string `json:"protocol"`
           47 
           48         // IsPlainText decides whether to use text/template or html/template
           49         // as template parser.
           50         IsPlainText bool `json:"isPlainText"`
           51 
           52         // IsHTML returns whether this format is int the HTML family. This includes
           53         // HTML, AMP etc. This is used to decide when to create alias redirects etc.
           54         IsHTML bool `json:"isHTML"`
           55 
           56         // Enable to ignore the global uglyURLs setting.
           57         NoUgly bool `json:"noUgly"`
           58 
           59         // Enable to override the global uglyURLs setting.
           60         Ugly bool `json:"ugly"`
           61 
           62         // Enable if it doesn't make sense to include this format in an alternative
           63         // format listing, CSS being one good example.
           64         // Note that we use the term "alternative" and not "alternate" here, as it
           65         // does not necessarily replace the other format, it is an alternative representation.
           66         NotAlternative bool `json:"notAlternative"`
           67 
           68         // Eneable if this is a resource which path always starts at the root,
           69         // e.g. /robots.txt.
           70         Root bool `json:"root"`
           71 
           72         // Setting this will make this output format control the value of
           73         // .Permalink and .RelPermalink for a rendered Page.
           74         // If not set, these values will point to the main (first) output format
           75         // configured. That is probably the behavior you want in most situations,
           76         // as you probably don't want to link back to the RSS version of a page, as an
           77         // example. AMP would, however, be a good example of an output format where this
           78         // behavior is wanted.
           79         Permalinkable bool `json:"permalinkable"`
           80 
           81         // Setting this to a non-zero value will be used as the first sort criteria.
           82         Weight int `json:"weight"`
           83 }
           84 
           85 // Built-in output formats.
           86 var (
           87         AMPFormat = Format{
           88                 Name:          "amp",
           89                 MediaType:     media.Builtin.HTMLType,
           90                 BaseName:      "index",
           91                 Path:          "amp",
           92                 Rel:           "amphtml",
           93                 IsHTML:        true,
           94                 Permalinkable: true,
           95                 // See https://www.ampproject.org/learn/overview/
           96         }
           97 
           98         CalendarFormat = Format{
           99                 Name:        "calendar",
          100                 MediaType:   media.Builtin.CalendarType,
          101                 IsPlainText: true,
          102                 Protocol:    "webcal://",
          103                 BaseName:    "index",
          104                 Rel:         "alternate",
          105         }
          106 
          107         CSSFormat = Format{
          108                 Name:           "css",
          109                 MediaType:      media.Builtin.CSSType,
          110                 BaseName:       "styles",
          111                 IsPlainText:    true,
          112                 Rel:            "stylesheet",
          113                 NotAlternative: true,
          114         }
          115         CSVFormat = Format{
          116                 Name:        "csv",
          117                 MediaType:   media.Builtin.CSVType,
          118                 BaseName:    "index",
          119                 IsPlainText: true,
          120                 Rel:         "alternate",
          121         }
          122 
          123         HTMLFormat = Format{
          124                 Name:          "html",
          125                 MediaType:     media.Builtin.HTMLType,
          126                 BaseName:      "index",
          127                 Rel:           "canonical",
          128                 IsHTML:        true,
          129                 Permalinkable: true,
          130 
          131                 // Weight will be used as first sort criteria. HTML will, by default,
          132                 // be rendered first, but set it to 10 so it's easy to put one above it.
          133                 Weight: 10,
          134         }
          135 
          136         // Alias is the output format used for alias redirects.
          137         AliasHTMLFormat = Format{
          138                 Name:          "alias",
          139                 MediaType:     media.Builtin.HTMLType,
          140                 IsHTML:        true,
          141                 Ugly:          true,
          142                 Permalinkable: false,
          143         }
          144 
          145         MarkdownFormat = Format{
          146                 Name:        "markdown",
          147                 MediaType:   media.Builtin.MarkdownType,
          148                 BaseName:    "index",
          149                 Rel:         "alternate",
          150                 IsPlainText: true,
          151         }
          152 
          153         JSONFormat = Format{
          154                 Name:        "json",
          155                 MediaType:   media.Builtin.JSONType,
          156                 BaseName:    "index",
          157                 IsPlainText: true,
          158                 Rel:         "alternate",
          159         }
          160 
          161         WebAppManifestFormat = Format{
          162                 Name:           "webappmanifest",
          163                 MediaType:      media.Builtin.WebAppManifestType,
          164                 BaseName:       "manifest",
          165                 IsPlainText:    true,
          166                 NotAlternative: true,
          167                 Rel:            "manifest",
          168         }
          169 
          170         RobotsTxtFormat = Format{
          171                 Name:        "robots",
          172                 MediaType:   media.Builtin.TextType,
          173                 BaseName:    "robots",
          174                 IsPlainText: true,
          175                 Root:        true,
          176                 Rel:         "alternate",
          177         }
          178 
          179         RSSFormat = Format{
          180                 Name:      "rss",
          181                 MediaType: media.Builtin.RSSType,
          182                 BaseName:  "index",
          183                 NoUgly:    true,
          184                 Rel:       "alternate",
          185         }
          186 
          187         SitemapFormat = Format{
          188                 Name:      "sitemap",
          189                 MediaType: media.Builtin.XMLType,
          190                 BaseName:  "sitemap",
          191                 Ugly:      true,
          192                 Rel:       "sitemap",
          193         }
          194 
          195         SitemapIndexFormat = Format{
          196                 Name:      "sitemapindex",
          197                 MediaType: media.Builtin.XMLType,
          198                 BaseName:  "sitemap",
          199                 Ugly:      true,
          200                 Root:      true,
          201                 Rel:       "sitemap",
          202         }
          203 
          204         GotmplFormat = Format{
          205                 Name:           "gotmpl",
          206                 MediaType:      media.Builtin.GotmplType,
          207                 IsPlainText:    true,
          208                 NotAlternative: true,
          209         }
          210 
          211         // I'm not sure having a 404 format is a good idea,
          212         // for one, we would want to have multiple formats for this.
          213         HTTPStatus404HTMLFormat = Format{
          214                 Name:           "404",
          215                 MediaType:      media.Builtin.HTMLType,
          216                 NotAlternative: true,
          217                 Ugly:           true,
          218                 IsHTML:         true,
          219                 Permalinkable:  true,
          220         }
          221 )
          222 
          223 // DefaultFormats contains the default output formats supported by Hugo.
          224 var DefaultFormats = Formats{
          225         AMPFormat,
          226         CalendarFormat,
          227         CSSFormat,
          228         CSVFormat,
          229         HTMLFormat,
          230         GotmplFormat,
          231         HTTPStatus404HTMLFormat,
          232         AliasHTMLFormat,
          233         JSONFormat,
          234         MarkdownFormat,
          235         WebAppManifestFormat,
          236         RobotsTxtFormat,
          237         RSSFormat,
          238         SitemapFormat,
          239         SitemapIndexFormat,
          240 }
          241 
          242 func init() {
          243         sort.Sort(DefaultFormats)
          244 }
          245 
          246 // Formats is a slice of Format.
          247 // <docsmeta>{ "name": "OutputFormats" }</docsmeta>
          248 type Formats []Format
          249 
          250 func (formats Formats) Len() int      { return len(formats) }
          251 func (formats Formats) Swap(i, j int) { formats[i], formats[j] = formats[j], formats[i] }
          252 func (formats Formats) Less(i, j int) bool {
          253         fi, fj := formats[i], formats[j]
          254         if fi.Weight == fj.Weight {
          255                 return fi.Name < fj.Name
          256         }
          257 
          258         if fj.Weight == 0 {
          259                 return true
          260         }
          261 
          262         return fi.Weight > 0 && fi.Weight < fj.Weight
          263 }
          264 
          265 // GetBySuffix gets a output format given as suffix, e.g. "html".
          266 // It will return false if no format could be found, or if the suffix given
          267 // is ambiguous.
          268 // The lookup is case insensitive.
          269 func (formats Formats) GetBySuffix(suffix string) (f Format, found bool) {
          270         for _, ff := range formats {
          271                 for _, suffix2 := range ff.MediaType.Suffixes() {
          272                         if strings.EqualFold(suffix, suffix2) {
          273                                 if found {
          274                                         // ambiguous
          275                                         found = false
          276                                         return
          277                                 }
          278                                 f = ff
          279                                 found = true
          280                         }
          281                 }
          282         }
          283         return
          284 }
          285 
          286 // GetByName gets a format by its identifier name.
          287 func (formats Formats) GetByName(name string) (f Format, found bool) {
          288         for _, ff := range formats {
          289                 if strings.EqualFold(name, ff.Name) {
          290                         f = ff
          291                         found = true
          292                         return
          293                 }
          294         }
          295         return
          296 }
          297 
          298 // GetByNames gets a list of formats given a list of identifiers.
          299 func (formats Formats) GetByNames(names ...string) (Formats, error) {
          300         var types []Format
          301 
          302         for _, name := range names {
          303                 tpe, ok := formats.GetByName(name)
          304                 if !ok {
          305                         return types, fmt.Errorf("OutputFormat with key %q not found", name)
          306                 }
          307                 types = append(types, tpe)
          308         }
          309         return types, nil
          310 }
          311 
          312 // FromFilename gets a Format given a filename.
          313 func (formats Formats) FromFilename(filename string) (f Format, found bool) {
          314         // mytemplate.amp.html
          315         // mytemplate.html
          316         // mytemplate
          317         var ext, outFormat string
          318 
          319         parts := strings.Split(filename, ".")
          320         if len(parts) > 2 {
          321                 outFormat = parts[1]
          322                 ext = parts[2]
          323         } else if len(parts) > 1 {
          324                 ext = parts[1]
          325         }
          326 
          327         if outFormat != "" {
          328                 return formats.GetByName(outFormat)
          329         }
          330 
          331         if ext != "" {
          332                 f, found = formats.GetBySuffix(ext)
          333                 if !found && len(parts) == 2 {
          334                         // For extensionless output formats (e.g. Netlify's _redirects)
          335                         // we must fall back to using the extension as format lookup.
          336                         f, found = formats.GetByName(ext)
          337                 }
          338         }
          339         return
          340 }
          341 
          342 // BaseFilename returns the base filename of f including an extension (ie.
          343 // "index.xml").
          344 func (f Format) BaseFilename() string {
          345         return f.BaseName + f.MediaType.FirstSuffix.FullSuffix
          346 }
          347 
          348 // IsZero returns true if f represents a zero value.
          349 func (f Format) IsZero() bool {
          350         return f.Name == ""
          351 }
          352 
          353 // MarshalJSON returns the JSON encoding of f.
          354 // For internal use only.
          355 func (f Format) MarshalJSON() ([]byte, error) {
          356         type Alias Format
          357         return json.Marshal(&struct {
          358                 MediaType string `json:"mediaType"`
          359                 Alias
          360         }{
          361                 MediaType: f.MediaType.String(),
          362                 Alias:     (Alias)(f),
          363         })
          364 }