}
if ident, ok := m.Type.(*ast.Ident); ok && ident.Obj != nil {
- // Embedded interface
- methodNames = append(
- methodNames,
- collectMethodsRecursive(
- pkg,
- ident.Obj.Decl.(*ast.TypeSpec).Type.(*ast.InterfaceType).Methods.List)...)
+ switch tt := ident.Obj.Decl.(*ast.TypeSpec).Type.(type) {
+ case *ast.InterfaceType:
+ // Embedded interface
+ methodNames = append(
+ methodNames,
+ collectMethodsRecursive(
+ pkg,
+ tt.Methods.List)...)
+ }
+
} else {
// Embedded, but in a different file/package. Return the
// package.Name and deal with that later.
Lang string `json:"lang,omitempty"`
}
+// MarshalJSON is for internal use only.
func (m *modMounts) MarshalJSON() ([]byte, error) {
var mounts []modMount
--- /dev/null
+// Package common provides common helper functionality for Hugo.
+package common
// Scratcher provides a scratching service.
type Scratcher interface {
+ // Scratch returns a "scratch pad" that can be used to store state.
Scratch() *Scratch
}
}
return fmt.Sprintf("%s%s{%s}", n.Name, FilePathSeparator, strings.Join(n.Slice, ","))
}
+
+// DirFile holds the result from path.Split.
+type DirFile struct {
+ Dir string
+ File string
+}
+
+// Used in test.
+func (df DirFile) String() string {
+ return fmt.Sprintf("%s|%s", df.Dir, df.File)
+}
// Positioner represents a thing that knows its position in a text file or stream,
// typically an error.
type Positioner interface {
+ // Position returns the current position.
+ // Useful in error logging, e.g. {{ errorf "error in code block: %s" .Position }}.
Position() Position
}
patternsStrings []string
}
+// MarshalJSON is for internal use only.
func (w Whitelist) MarshalJSON() ([]byte, error) {
if w.acceptNone {
return json.Marshal(acceptNoneKeyword)
type FileMetaInfo interface {
os.FileInfo
+ // Meta is for internal use.
Meta() *FileMeta
}
}
func (m *pageMap) createSiteTaxonomies() error {
- m.s.taxonomies = make(TaxonomyList)
+ m.s.taxonomies = make(page.TaxonomyList)
var walkErr error
m.taxonomies.Walk(func(s string, v any) bool {
n := v.(*contentNode)
viewName := t.name
if t.termKey == "" {
- m.s.taxonomies[viewName.plural] = make(Taxonomy)
+ m.s.taxonomies[viewName.plural] = make(page.Taxonomy)
} else {
taxonomy := m.s.taxonomies[viewName.plural]
if taxonomy == nil {
m.taxonomyEntries.WalkPrefix(s, func(ss string, v any) bool {
b2 := v.(*contentNode)
info := b2.viewInfo
- taxonomy.add(info.termKey, page.NewWeightedPage(info.weight, info.ref.p, n.p))
+ taxonomy[info.termKey] = append(taxonomy[info.termKey], page.NewWeightedPage(info.weight, info.ref.p, n.p))
return false
})
"github.com/bep/gitmap"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/resources/page"
+ "github.com/gohugoio/hugo/source"
)
type gitInfo struct {
repo *gitmap.GitRepo
}
-func (g *gitInfo) forPage(p page.Page) *gitmap.GitInfo {
+func (g *gitInfo) forPage(p page.Page) source.GitInfo {
name := strings.TrimPrefix(filepath.ToSlash(p.File().Filename()), g.contentDir)
name = strings.TrimPrefix(name, "/")
-
- return g.repo.Files[name]
+ gi, found := g.repo.Files[name]
+ if !found {
+ return source.GitInfo{}
+ }
+ return source.NewGitInfo(*gi)
}
func newGitInfo(cfg config.Provider) (*gitInfo, error) {
"github.com/gohugoio/hugo/source"
- "github.com/bep/gitmap"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/publisher"
return h.data
}
-func (h *HugoSites) gitInfoForPage(p page.Page) (*gitmap.GitInfo, error) {
+func (h *HugoSites) gitInfoForPage(p page.Page) (source.GitInfo, error) {
if _, err := h.init.gitInfo.Do(); err != nil {
- return nil, err
+ return source.GitInfo{}, err
}
if h.gitInfo == nil {
- return nil, nil
+ return source.GitInfo{}, nil
}
return h.gitInfo.forPage(p), nil
"github.com/gohugoio/hugo/hugofs/files"
- "github.com/bep/gitmap"
-
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/common/herrors"
return identity.NewPathIdentity(files.ComponentFolderContent, filepath.FromSlash(p.Pathc()))
}
-func (p *pageState) GitInfo() *gitmap.GitInfo {
+func (p *pageState) GitInfo() source.GitInfo {
return p.gitInfo
}
import (
"sync"
- "github.com/bep/gitmap"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/compare"
"github.com/gohugoio/hugo/lazy"
"github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/resources/page"
"github.com/gohugoio/hugo/resources/resource"
+ "github.com/gohugoio/hugo/source"
)
type treeRefProvider interface {
shortcodeState *shortcodeHandler
// Set if feature enabled and this is in a Git repo.
- gitInfo *gitmap.GitInfo
+ gitInfo source.GitInfo
codeowners []string
// Positional navigation
}
var gitAuthorDate time.Time
- if p.gitInfo != nil {
+ if !p.gitInfo.IsZero() {
gitAuthorDate = p.gitInfo.AuthorDate
}
*PageCollections
- taxonomies TaxonomyList
+ taxonomies page.TaxonomyList
- Sections Taxonomy
+ Sections page.Taxonomy
Info *SiteInfo
language *langs.Language
init *siteInit
}
-func (s *Site) Taxonomies() TaxonomyList {
+func (s *Site) Taxonomies() page.TaxonomyList {
s.init.taxonomies.Do()
return s.taxonomies
}
}
// TODO(bep) type
-func (s *SiteInfo) Taxonomies() any {
+func (s *SiteInfo) Taxonomies() page.TaxonomyList {
return s.s.Taxonomies()
}
+++ /dev/null
-// Copyright 2019 The Hugo Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package hugolib
-
-import (
- "fmt"
- "sort"
-
- "github.com/gohugoio/hugo/compare"
- "github.com/gohugoio/hugo/langs"
-
- "github.com/gohugoio/hugo/resources/page"
-)
-
-// The TaxonomyList is a list of all taxonomies and their values
-// e.g. List['tags'] => TagTaxonomy (from above)
-type TaxonomyList map[string]Taxonomy
-
-func (tl TaxonomyList) String() string {
- return fmt.Sprintf("TaxonomyList(%d)", len(tl))
-}
-
-// A Taxonomy is a map of keywords to a list of pages.
-// For example
-// TagTaxonomy['technology'] = page.WeightedPages
-// TagTaxonomy['go'] = page.WeightedPages
-type Taxonomy map[string]page.WeightedPages
-
-// OrderedTaxonomy is another representation of an Taxonomy using an array rather than a map.
-// Important because you can't order a map.
-type OrderedTaxonomy []OrderedTaxonomyEntry
-
-// getOneOPage returns one page in the taxonomy,
-// nil if there is none.
-func (t OrderedTaxonomy) getOneOPage() page.Page {
- if len(t) == 0 {
- return nil
- }
- return t[0].Pages()[0]
-}
-
-// OrderedTaxonomyEntry is similar to an element of a Taxonomy, but with the key embedded (as name)
-// e.g: {Name: Technology, page.WeightedPages: TaxonomyPages}
-type OrderedTaxonomyEntry struct {
- Name string
- page.WeightedPages
-}
-
-// Get the weighted pages for the given key.
-func (i Taxonomy) Get(key string) page.WeightedPages {
- return i[key]
-}
-
-// Count the weighted pages for the given key.
-func (i Taxonomy) Count(key string) int { return len(i[key]) }
-
-func (i Taxonomy) add(key string, w page.WeightedPage) {
- i[key] = append(i[key], w)
-}
-
-// TaxonomyArray returns an ordered taxonomy with a non defined order.
-func (i Taxonomy) TaxonomyArray() OrderedTaxonomy {
- ies := make([]OrderedTaxonomyEntry, len(i))
- count := 0
- for k, v := range i {
- ies[count] = OrderedTaxonomyEntry{Name: k, WeightedPages: v}
- count++
- }
- return ies
-}
-
-// Alphabetical returns an ordered taxonomy sorted by key name.
-func (i Taxonomy) Alphabetical() OrderedTaxonomy {
- ia := i.TaxonomyArray()
- p := ia.getOneOPage()
- if p == nil {
- return ia
- }
- currentSite := p.Site().Current()
- coll := langs.GetCollator(currentSite.Language())
- coll.Lock()
- defer coll.Unlock()
- name := func(i1, i2 *OrderedTaxonomyEntry) bool {
- return coll.CompareStrings(i1.Name, i2.Name) < 0
- }
- oiBy(name).Sort(ia)
- return ia
-}
-
-// ByCount returns an ordered taxonomy sorted by # of pages per key.
-// If taxonomies have the same # of pages, sort them alphabetical
-func (i Taxonomy) ByCount() OrderedTaxonomy {
- count := func(i1, i2 *OrderedTaxonomyEntry) bool {
- li1 := len(i1.WeightedPages)
- li2 := len(i2.WeightedPages)
-
- if li1 == li2 {
- return compare.LessStrings(i1.Name, i2.Name)
- }
- return li1 > li2
- }
-
- ia := i.TaxonomyArray()
- oiBy(count).Sort(ia)
- return ia
-}
-
-// Pages returns the Pages for this taxonomy.
-func (ie OrderedTaxonomyEntry) Pages() page.Pages {
- return ie.WeightedPages.Pages()
-}
-
-// Count returns the count the pages in this taxonomy.
-func (ie OrderedTaxonomyEntry) Count() int {
- return len(ie.WeightedPages)
-}
-
-// Term returns the name given to this taxonomy.
-func (ie OrderedTaxonomyEntry) Term() string {
- return ie.Name
-}
-
-// Reverse reverses the order of the entries in this taxonomy.
-func (t OrderedTaxonomy) Reverse() OrderedTaxonomy {
- for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 {
- t[i], t[j] = t[j], t[i]
- }
-
- return t
-}
-
-// A type to implement the sort interface for TaxonomyEntries.
-type orderedTaxonomySorter struct {
- taxonomy OrderedTaxonomy
- by oiBy
-}
-
-// Closure used in the Sort.Less method.
-type oiBy func(i1, i2 *OrderedTaxonomyEntry) bool
-
-func (by oiBy) Sort(taxonomy OrderedTaxonomy) {
- ps := &orderedTaxonomySorter{
- taxonomy: taxonomy,
- by: by, // The Sort method's receiver is the function (closure) that defines the sort order.
- }
- sort.Stable(ps)
-}
-
-// Len is part of sort.Interface.
-func (s *orderedTaxonomySorter) Len() int {
- return len(s.taxonomy)
-}
-
-// Swap is part of sort.Interface.
-func (s *orderedTaxonomySorter) Swap(i, j int) {
- s.taxonomy[i], s.taxonomy[j] = s.taxonomy[j], s.taxonomy[i]
-}
-
-// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
-func (s *orderedTaxonomySorter) Less(i, j int) bool {
- return s.by(&s.taxonomy[i], &s.taxonomy[j])
-}
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package langs contains the language related types and function.
package langs
import (
var _ AttributesOptionsSliceProvider = (*attributes.AttributesHolder)(nil)
type AttributesProvider interface {
+ // Attributes passed in from Markdown (e.g. { attrName1=attrValue1 attrName2="attr Value 2" }).
Attributes() map[string]any
}
type LinkContext interface {
+ // The Page being rendered.
Page() any
+
+ // The link URL.
Destination() string
+
+ // The link title attribute.
Title() string
+
+ // The rendered (HTML) text.
Text() hstring.RenderedString
+
+ // The plain variant of Text.
PlainText() string
}
type ImageLinkContext interface {
LinkContext
+
+ // Returns true if this is a standalone image and the config option
+ // markup.goldmark.parser.wrapStandAloneImageWithinParagraph is disabled.
IsBlock() bool
+
+ // Zero-based ordinal for all the images in the current document.
Ordinal() int
}
+// CodeblockContext is the context passed to a code block render hook.
type CodeblockContext interface {
AttributesProvider
text.Positioner
+
+ // Chroma highlighting processing options. This will only be filled if Type is a known Chroma Lexer.
Options() map[string]any
+
+ // The type of code block. This will be the programming language, e.g. bash, when doing code highlighting.
Type() string
+
+ // The text between the code fences.
Inner() string
+
+ // Zero-based ordinal for all code blocks in the current document.
Ordinal() int
+
+ // The owning Page.
Page() any
}
highlighted template.HTML
}
+// Wrapped returns the highlighted code wrapped in a <div>, <pre> and <code> tag.
func (h HightlightResult) Wrapped() template.HTML {
return h.highlighted
}
+// Inner returns the highlighted code without the wrapping <div>, <pre> and <code> tag, suitable for inline use.
func (h HightlightResult) Inner() template.HTML {
return h.highlighted[h.innerLow:h.innerHigh]
}
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package markup contains the markup handling (e.g. Markdown).
package markup
import (
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package media containes Media Type (MIME type) related types and functions.
package media
import (
-// Copyright 2019 The Hugo Authors. All rights reserved.
+// Copyright 2023 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package navigation provides the menu functionality.
package navigation
import (
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+
package navigation
import (
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package output contains Output Format types and functions.
package output
import (
}
// MarshalJSON returns the JSON encoding of f.
+// For internal use only.
func (f Format) MarshalJSON() ([]byte, error) {
type Alias Format
return json.Marshal(&struct {
--- /dev/null
+// Copyright 2023 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package resources contains Resource related types.
+package resources
}
}
+// Tags is a map of EXIF tags.
type Tags map[string]any
+// UnmarshalJSON is for internal use only.
func (v *Tags) UnmarshalJSON(b []byte) error {
vv := make(map[string]any)
if err := tcodec.Unmarshal(b, &vv); err != nil {
return nil
}
+// MarshalJSON is for internal use only.
func (v Tags) MarshalJSON() ([]byte, error) {
return tcodec.Marshal(v)
}
type ImageResourceOps interface {
// Height returns the height of the Image.
Height() int
+
// Width returns the width of the Image.
Width() int
// Use the anchor option to change the crop box anchor point.
// {{ $image := $image.Crop "600x400" }}
Crop(spec string) (ImageResource, error)
+
+ // Fill scales the image to the smallest possible size that will cover the specified dimensions in spec,
+ // crops the resized image to the specified dimensions using the given anchor point.
+ // The spec is space delimited, e.g. `200x300 TopLeft`.
Fill(spec string) (ImageResource, error)
+
+ // Fit scales down the image using the given spec.
Fit(spec string) (ImageResource, error)
+
+ // Resize resizes the image to the given spec. If one of width or height is 0, the image aspect
+ // ratio is preserved.
Resize(spec string) (ImageResource, error)
// Filter applies one or more filters to an Image.
"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/markup/converter"
- "github.com/bep/gitmap"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/tpl"
// ChildCareProvider provides accessors to child resources.
type ChildCareProvider interface {
+ // Pages returns a list of pages of all kinds.
Pages() Pages
// RegularPages returns a list of pages of kind 'Page'.
- // In Hugo 0.57 we changed the Pages method so it returns all page
- // kinds, even sections. If you want the old behaviour, you can
- // use RegularPages.
RegularPages() Pages
// RegularPagesRecursive returns all regular pages below the current
// section.
RegularPagesRecursive() Pages
+ // Resources returns a list of all resources.
Resources() resource.Resources
}
ReadingTime() int
// Len returns the length of the content.
+ // This is for internal use only.
Len() int
}
// ContentRenderer provides the content rendering methods for some content.
type ContentRenderer interface {
+ // RenderContent renders the given content.
+ // For internal use only.
RenderContent(content []byte, renderTOC bool) (converter.Result, error)
}
// FileProvider provides the source file.
type FileProvider interface {
+ // File returns the source file for this Page,
+ // or a zero File if this Page is not backed by a file.
File() source.File
}
// GitInfoProvider provides Git info.
type GitInfoProvider interface {
- GitInfo() *gitmap.GitInfo
+ // GitInfo returns the Git info for this object.
+ GitInfo() source.GitInfo
+ // CodeOwners returns the code owners for this object.
CodeOwners() []string
}
// InSectionPositioner provides section navigation.
type InSectionPositioner interface {
+ // NextInSection returns the next page in the same section.
NextInSection() Page
+ // PrevInSection returns the previous page in the same section.
PrevInSection() Page
}
// OutputFormatsProvider provides the OutputFormats of a Page.
type OutputFormatsProvider interface {
+ // OutputFormats returns the OutputFormats for this Page.
OutputFormats() OutputFormats
}
SectionsPath() string
// Sitemap returns the sitemap configuration for this page.
+ // This is for internal use only.
Sitemap() config.Sitemap
// Type is a discriminator used to select layouts etc. It is typically set
// PageRenderProvider provides a way for a Page to render content.
type PageRenderProvider interface {
+ // Render renders the given layout with this Page as context.
Render(layout ...string) (template.HTML, error)
+ // RenderString renders the first value in args with tPaginatorhe content renderer defined
+ // for this Page.
+ // It takes an optional map as a second argument:
+ //
+ // display (“inline”):
+ // - inline or block. If inline (default), surrounding <p></p> on short snippets will be trimmed.
+ // markup (defaults to the Page’s markup)
RenderString(args ...any) (template.HTML, error)
}
// Positioner provides next/prev navigation.
type Positioner interface {
+ // Next points up to the next regular page (sorted by Hugo’s default sort).
Next() Page
+ // Prev points down to the previous regular page (sorted by Hugo’s default sort).
Prev() Page
// Deprecated: Use Prev. Will be removed in Hugo 0.57
// RawContentProvider provides the raw, unprocessed content of the page.
type RawContentProvider interface {
+ // RawContent returns the raw, unprocessed content of the page excluding any front matter.
RawContent() string
}
// RefProvider provides the methods needed to create reflinks to pages.
type RefProvider interface {
+ // Ref returns an absolute URl to a page.
Ref(argsm map[string]any) (string, error)
// RefFrom is for internal use only.
RefFrom(argsm map[string]any, source any) (string, error)
+ // RelRef returns a relative URL to a page.
RelRef(argsm map[string]any) (string, error)
// RefFrom is for internal use only.
// SitesProvider provide accessors to get sites.
type SitesProvider interface {
+ // Site returns the current site.
Site() Site
+ // Sites returns all sites.
Sites() Sites
}
// TableOfContentsProvider provides the table of contents for a Page.
type TableOfContentsProvider interface {
+ // TableOfContents returns the table of contents for the page rendered as HTML.
TableOfContents() template.HTML
}
// TreeProvider provides section tree navigation.
type TreeProvider interface {
- // IsAncestor returns whether the current page is an ancestor of the given
+ // IsAncestor returns whether the current page is an ancestor of other.
// Note that this method is not relevant for taxonomy lists and taxonomy terms pages.
IsAncestor(other any) (bool, error)
// Note that this will return nil for pages that is not regular, home or section pages.
CurrentSection() Page
- // IsDescendant returns whether the current page is a descendant of the given
+ // IsDescendant returns whether the current page is a descendant of other.
// Note that this method is not relevant for taxonomy lists and taxonomy terms pages.
IsDescendant(other any) (bool, error)
// For the home page, this will return itself.
FirstSection() Page
- // InSection returns whether the given page is in the current section.
+ // InSection returns whether other is in the current section.
// Note that this will always return false for pages that are
// not either regular, home or section pages.
InSection(other any) (bool, error)
import (
"encoding/json"
- "github.com/bep/gitmap"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/hugofs/files"
language := p.Language()
file := p.File()
gitInfo := p.GitInfo()
+ codeOwners := p.CodeOwners()
outputFormats := p.OutputFormats()
alternativeOutputFormats := p.AlternativeOutputFormats()
menus := p.Menus()
isTranslated := p.IsTranslated()
allTranslations := p.AllTranslations()
translations := p.Translations()
+ store := p.Store()
getIdentity := p.GetIdentity()
s := struct {
- Content any
+ Content interface{}
Plain string
PlainWords []string
Summary template.HTML
Name string
Title string
Params maps.Params
- Data any
+ Data interface{}
Date time.Time
Lastmod time.Time
PublishDate time.Time
Weight int
Language *langs.Language
File source.File
- GitInfo *gitmap.GitInfo
+ GitInfo source.GitInfo
+ CodeOwners []string
OutputFormats OutputFormats
AlternativeOutputFormats OutputFormats
Menus navigation.PageMenus
IsTranslated bool
AllTranslations Pages
Translations Pages
+ Store *maps.Scratch
GetIdentity identity.Identity
}{
Content: content,
Language: language,
File: file,
GitInfo: gitInfo,
+ CodeOwners: codeOwners,
OutputFormats: outputFormats,
AlternativeOutputFormats: alternativeOutputFormats,
Menus: menus,
IsTranslated: isTranslated,
AllTranslations: allTranslations,
Translations: translations,
+ Store: store,
GetIdentity: getIdentity,
}
"github.com/gohugoio/hugo/hugofs"
- "github.com/bep/gitmap"
"github.com/gohugoio/hugo/navigation"
"github.com/gohugoio/hugo/common/hugo"
return nil
}
-func (p *nopPage) GitInfo() *gitmap.GitInfo {
- return nil
+func (p *nopPage) GitInfo() source.GitInfo {
+ return source.GitInfo{}
}
func (p *nopPage) CodeOwners() []string {
// PaginatorProvider provides two ways to create a page paginator.
type PaginatorProvider interface {
+ // Paginator creates a paginator with the default page set.
Paginator(options ...any) (*Pager, error)
- Paginate(seq any, options ...any) (*Pager, error)
+ // Paginate creates a paginator with the given page set in pages.
+ Paginate(pages any, options ...any) (*Pager, error)
}
// Pager represents one of the elements in a paginator.
"github.com/gohugoio/hugo/navigation"
)
-// Site represents a site in the build. This is currently a very narrow interface,
-// but the actual implementation will be richer, see hugolib.SiteInfo.
+// Site represents a site. There can be multople sites in a multilingual setup.
type Site interface {
// Returns the Language configured for this Site.
Language() *langs.Language
BaseURL() template.URL
// Retuns a taxonomy map.
- Taxonomies() any
+ Taxonomies() TaxonomyList
// Returns the last modification date of the content.
LastChange() time.Time
return nil
}
-func (t testSite) Taxonomies() any {
+func (t testSite) Taxonomies() TaxonomyList {
return nil
}
--- /dev/null
+// Copyright 2023 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package page
+
+import (
+ "fmt"
+ "sort"
+
+ "github.com/gohugoio/hugo/compare"
+ "github.com/gohugoio/hugo/langs"
+)
+
+// The TaxonomyList is a list of all taxonomies and their values
+// e.g. List['tags'] => TagTaxonomy (from above)
+type TaxonomyList map[string]Taxonomy
+
+func (tl TaxonomyList) String() string {
+ return fmt.Sprintf("TaxonomyList(%d)", len(tl))
+}
+
+// A Taxonomy is a map of keywords to a list of pages.
+// For example
+//
+// TagTaxonomy['technology'] = WeightedPages
+// TagTaxonomy['go'] = WeightedPages
+type Taxonomy map[string]WeightedPages
+
+// OrderedTaxonomy is another representation of an Taxonomy using an array rather than a map.
+// Important because you can't order a map.
+type OrderedTaxonomy []OrderedTaxonomyEntry
+
+// getOneOPage returns one page in the taxonomy,
+// nil if there is none.
+func (t OrderedTaxonomy) getOneOPage() Page {
+ if len(t) == 0 {
+ return nil
+ }
+ return t[0].Pages()[0]
+}
+
+// OrderedTaxonomyEntry is similar to an element of a Taxonomy, but with the key embedded (as name)
+// e.g: {Name: Technology, WeightedPages: TaxonomyPages}
+type OrderedTaxonomyEntry struct {
+ Name string
+ WeightedPages
+}
+
+// Get the weighted pages for the given key.
+func (i Taxonomy) Get(key string) WeightedPages {
+ return i[key]
+}
+
+// Count the weighted pages for the given key.
+func (i Taxonomy) Count(key string) int { return len(i[key]) }
+
+// TaxonomyArray returns an ordered taxonomy with a non defined order.
+func (i Taxonomy) TaxonomyArray() OrderedTaxonomy {
+ ies := make([]OrderedTaxonomyEntry, len(i))
+ count := 0
+ for k, v := range i {
+ ies[count] = OrderedTaxonomyEntry{Name: k, WeightedPages: v}
+ count++
+ }
+ return ies
+}
+
+// Alphabetical returns an ordered taxonomy sorted by key name.
+func (i Taxonomy) Alphabetical() OrderedTaxonomy {
+ ia := i.TaxonomyArray()
+ p := ia.getOneOPage()
+ if p == nil {
+ return ia
+ }
+ currentSite := p.Site().Current()
+ coll := langs.GetCollator(currentSite.Language())
+ coll.Lock()
+ defer coll.Unlock()
+ name := func(i1, i2 *OrderedTaxonomyEntry) bool {
+ return coll.CompareStrings(i1.Name, i2.Name) < 0
+ }
+ oiBy(name).Sort(ia)
+ return ia
+}
+
+// ByCount returns an ordered taxonomy sorted by # of pages per key.
+// If taxonomies have the same # of pages, sort them alphabetical
+func (i Taxonomy) ByCount() OrderedTaxonomy {
+ count := func(i1, i2 *OrderedTaxonomyEntry) bool {
+ li1 := len(i1.WeightedPages)
+ li2 := len(i2.WeightedPages)
+
+ if li1 == li2 {
+ return compare.LessStrings(i1.Name, i2.Name)
+ }
+ return li1 > li2
+ }
+
+ ia := i.TaxonomyArray()
+ oiBy(count).Sort(ia)
+ return ia
+}
+
+// Pages returns the Pages for this taxonomy.
+func (ie OrderedTaxonomyEntry) Pages() Pages {
+ return ie.WeightedPages.Pages()
+}
+
+// Count returns the count the pages in this taxonomy.
+func (ie OrderedTaxonomyEntry) Count() int {
+ return len(ie.WeightedPages)
+}
+
+// Term returns the name given to this taxonomy.
+func (ie OrderedTaxonomyEntry) Term() string {
+ return ie.Name
+}
+
+// Reverse reverses the order of the entries in this taxonomy.
+func (t OrderedTaxonomy) Reverse() OrderedTaxonomy {
+ for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 {
+ t[i], t[j] = t[j], t[i]
+ }
+
+ return t
+}
+
+// A type to implement the sort interface for TaxonomyEntries.
+type orderedTaxonomySorter struct {
+ taxonomy OrderedTaxonomy
+ by oiBy
+}
+
+// Closure used in the Sort.Less method.
+type oiBy func(i1, i2 *OrderedTaxonomyEntry) bool
+
+func (by oiBy) Sort(taxonomy OrderedTaxonomy) {
+ ps := &orderedTaxonomySorter{
+ taxonomy: taxonomy,
+ by: by, // The Sort method's receiver is the function (closure) that defines the sort order.
+ }
+ sort.Stable(ps)
+}
+
+// Len is part of sort.Interface.
+func (s *orderedTaxonomySorter) Len() int {
+ return len(s.taxonomy)
+}
+
+// Swap is part of sort.Interface.
+func (s *orderedTaxonomySorter) Swap(i, j int) {
+ s.taxonomy[i], s.taxonomy[j] = s.taxonomy[j], s.taxonomy[i]
+}
+
+// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
+func (s *orderedTaxonomySorter) Less(i, j int) bool {
+ return s.by(&s.taxonomy[i], &s.taxonomy[j])
+}
"github.com/gohugoio/hugo/modules"
- "github.com/bep/gitmap"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/resources/resource"
return relatedDocsHandler
}
-func (p *testPage) GitInfo() *gitmap.GitInfo {
- return nil
+func (p *testPage) GitInfo() source.GitInfo {
+ return source.GitInfo{}
}
func (p *testPage) CodeOwners() []string {
-// Copyright 2019 The Hugo Authors. All rights reserved.
+// Copyright 2023 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package resource contains Resource related types.
package resource
import (
// ErrProvider provides an Err.
type ErrProvider interface {
+
+ // Err returns an error if this resource is in an error state.
+ // This will currently only be set for resources obtained from resources.GetRemote.
Err() ResourceError
}
"path/filepath"
"strings"
"sync"
+ "time"
+ "github.com/bep/gitmap"
"github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/hugofs/files"
return f, nil
}
+
+func NewGitInfo(info gitmap.GitInfo) GitInfo {
+ return GitInfo(info)
+}
+
+// GitInfo provides information about a version controled source file.
+type GitInfo struct {
+ // Commit hash.
+ Hash string `json:"hash"`
+ // Abbreviated commit hash.
+ AbbreviatedHash string `json:"abbreviatedHash"`
+ // The commit message's subject/title line.
+ Subject string `json:"subject"`
+ // The author name, respecting .mailmap.
+ AuthorName string `json:"authorName"`
+ // The author email address, respecting .mailmap.
+ AuthorEmail string `json:"authorEmail"`
+ // The author date.
+ AuthorDate time.Time `json:"authorDate"`
+ // The commit date.
+ CommitDate time.Time `json:"commitDate"`
+}
+
+// IsZero returns true if the GitInfo is empty,
+// meaning it will also be falsy in the Go templates.
+func (g GitInfo) IsZero() bool {
+ return g.Hash == ""
+}
-// Copyright 2017-present The Hugo Authors. All rights reserved.
+// Copyright 2023 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package source contains the types and functions related to source files.
package source
import (
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package diagrams provides template functions for generating diagrams.
package diagrams
import (
return config, nil
}
+// Filter applies the given filters to the image given as the last element in args.
func (ns *Namespace) Filter(args ...any) (images.ImageResource, error) {
if len(args) < 2 {
return nil, errors.New("must provide an image and one or more filters")
--- /dev/null
+// Package openapi provides functions for generating OpenAPI (Swagger) documentation.
+package openapi
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package openapi3 provides functions for generating OpenAPI v3 (Swagger) documentation.
package openapi3
import (
*kopenapi3.T
}
+// Unmarshal unmarshals the given resource into an OpenAPI 3 document.
func (ns *Namespace) Unmarshal(r resource.UnmarshableResource) (*OpenAPIDocument, error) {
key := r.Key()
if key == "" {
}{
{filepath.FromSlash("/f/f1.txt"), "f1-content"},
{filepath.FromSlash("f/f1.txt"), "f1-content"},
- {filepath.FromSlash("../f2.txt"), false},
+ {filepath.FromSlash("../f2.txt"), ""},
{"", false},
- {"b", false},
+ {"b", ""},
} {
result, err := ns.ReadFile(test.filename)
if bb, ok := test.expect.(bool); ok && !bb {
- b.Assert(err, qt.Not(qt.IsNil))
+ b.Assert(err, qt.Not(qt.IsNil), qt.Commentf("filename: %q", test.filename))
continue
}
package path
import (
- "fmt"
_path "path"
"path/filepath"
"strings"
+ "github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/deps"
"github.com/spf13/cast"
)
deps *deps.Deps
}
-// DirFile holds the result from path.Split.
-type DirFile struct {
- Dir string
- File string
-}
-
-// Used in test.
-func (df DirFile) String() string {
- return fmt.Sprintf("%s|%s", df.Dir, df.File)
-}
-
// Ext returns the file name extension used by path.
// The extension is the suffix beginning at the final dot
// in the final slash-separated element of path;
// The input path is passed into filepath.ToSlash converting any Windows slashes
// to forward slashes.
// The returned values have the property that path = dir+file.
-func (ns *Namespace) Split(path any) (DirFile, error) {
+func (ns *Namespace) Split(path any) (paths.DirFile, error) {
spath, err := cast.ToStringE(path)
if err != nil {
- return DirFile{}, err
+ return paths.DirFile{}, err
}
spath = filepath.ToSlash(spath)
dir, file := _path.Split(spath)
- return DirFile{Dir: dir, File: file}, nil
+ return paths.DirFile{Dir: dir, File: file}, nil
}
// Join joins any number of path elements into a single path, adding a
"testing"
qt "github.com/frankban/quicktest"
+ "github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/deps"
)
`baz/foo/bar.txt`,
},
{
- []any{"", "baz", DirFile{"big", "john"}, filepath.FromSlash(`foo/bar.txt`)},
+ []any{"", "baz", paths.DirFile{Dir: "big", File: "john"}, filepath.FromSlash(`foo/bar.txt`)},
`baz/big|john/foo/bar.txt`,
},
{nil, ""},
path any
expect any
}{
- {filepath.FromSlash(`foo/bar.txt`), DirFile{`foo/`, `bar.txt`}},
- {filepath.FromSlash(`foo/bar/txt `), DirFile{`foo/bar/`, `txt `}},
- {`foo.bar.txt`, DirFile{``, `foo.bar.txt`}},
- {``, DirFile{``, ``}},
+ {filepath.FromSlash(`foo/bar.txt`), paths.DirFile{Dir: `foo/`, File: `bar.txt`}},
+ {filepath.FromSlash(`foo/bar/txt `), paths.DirFile{Dir: `foo/bar/`, File: `txt `}},
+ {`foo.bar.txt`, paths.DirFile{Dir: ``, File: `foo.bar.txt`}},
+ {``, paths.DirFile{Dir: ``, File: ``}},
// errors
{tstNoStringer{}, false},
} {
return ns.postcssClient.Process(r, m)
}
+// PostProcess processes r after the build.
func (ns *Namespace) PostProcess(r resource.Resource) (postpub.PostPublishedResource, error) {
return ns.deps.ResourceSpec.PostProcess(r)
}
openTag bool
}
-// Truncate truncates a given string to the specified length.
-func (ns *Namespace) Truncate(a any, options ...any) (template.HTML, error) {
- length, err := cast.ToIntE(a)
+// Truncate truncates the string in s to the specified length.
+func (ns *Namespace) Truncate(s any, options ...any) (template.HTML, error) {
+ length, err := cast.ToIntE(s)
if err != nil {
return "", err
}
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package tpl contains template functions and related types.
package tpl
import (