}
const (
- CacheKeyGetJSON = "getjson"
- CacheKeyGetCSV = "getcsv"
CacheKeyImages = "images"
CacheKeyAssets = "assets"
CacheKeyModules = "modules"
MaxAge: 24 * time.Hour,
Dir: ":cacheDir/modules",
},
- CacheKeyGetJSON: defaultCacheConfig,
- CacheKeyGetCSV: defaultCacheConfig,
CacheKeyImages: {
MaxAge: -1,
Dir: resourcesGenDir,
})
}
-// GetJSONCache gets the file cache for getJSON.
-func (f Caches) GetJSONCache() *Cache {
- return f[CacheKeyGetJSON]
-}
-
-// GetCSVCache gets the file cache for getCSV.
-func (f Caches) GetCSVCache() *Cache {
- return f[CacheKeyGetCSV]
-}
-
// ImageCache gets the file cache for processed images.
func (f Caches) ImageCache() *Cache {
return f[CacheKeyImages]
archetypeDir = "archetypes"
[caches]
-[caches.getJSON]
+[caches.misc]
maxAge = "10m"
dir = "/path/to/c1"
-[caches.getCSV]
-maxAge = "11h"
-dir = "/path/to/c2"
[caches.images]
dir = "/path/to/c3"
[caches.getResource]
c.Assert(err, qt.IsNil)
fs := afero.NewMemMapFs()
decoded := testconfig.GetTestConfigs(fs, cfg).Base.Caches
- c.Assert(len(decoded), qt.Equals, 8)
+ c.Assert(len(decoded), qt.Equals, 6)
- c2 := decoded["getcsv"]
- c.Assert(c2.MaxAge.String(), qt.Equals, "11h0m0s")
- c.Assert(c2.DirCompiled, qt.Equals, filepath.FromSlash("/path/to/c2/filecache/getcsv"))
+ c2 := decoded["misc"]
+ c.Assert(c2.MaxAge.String(), qt.Equals, "10m0s")
+ c.Assert(c2.DirCompiled, qt.Equals, filepath.FromSlash("/path/to/c1/filecache/misc"))
c3 := decoded["images"]
c.Assert(c3.MaxAge, qt.Equals, time.Duration(-1))
ignoreCache = true
[caches]
-[caches.getJSON]
+[caches.misc]
maxAge = 1234
dir = "/path/to/c1"
-[caches.getCSV]
-maxAge = 3456
-dir = "/path/to/c2"
[caches.images]
dir = "/path/to/c3"
[caches.getResource]
c.Assert(err, qt.IsNil)
fs := afero.NewMemMapFs()
decoded := testconfig.GetTestConfigs(fs, cfg).Base.Caches
- c.Assert(len(decoded), qt.Equals, 8)
+ c.Assert(len(decoded), qt.Equals, 6)
for _, v := range decoded {
c.Assert(v.MaxAge, qt.Equals, time.Duration(0))
fs := afero.NewMemMapFs()
decoded := testconfig.GetTestConfigs(fs, cfg).Base.Caches
- c.Assert(len(decoded), qt.Equals, 8)
+ c.Assert(len(decoded), qt.Equals, 6)
imgConfig := decoded[filecache.CacheKeyImages]
- jsonConfig := decoded[filecache.CacheKeyGetJSON]
+ miscConfig := decoded[filecache.CacheKeyMisc]
if runtime.GOOS == "windows" {
c.Assert(imgConfig.DirCompiled, qt.Equals, filepath.FromSlash("_gen/images"))
} else {
c.Assert(imgConfig.DirCompiled, qt.Equals, "_gen/images")
- c.Assert(jsonConfig.DirCompiled, qt.Equals, "/cache/thecache/hugoproject/filecache/getjson")
+ c.Assert(miscConfig.DirCompiled, qt.Equals, "/cache/thecache/hugoproject/filecache/misc")
}
c.Assert(imgConfig.IsResourceDir, qt.Equals, true)
- c.Assert(jsonConfig.IsResourceDir, qt.Equals, false)
+ c.Assert(miscConfig.IsResourceDir, qt.Equals, false)
}
func TestFileCacheConfigMarshalJSON(t *testing.T) {
archeTypedir = "archetypes"
[caches]
-[caches.getjson]
+[caches.misc]
maxAge = "200ms"
dir = "/cache/c"
-[caches.getcsv]
-maxAge = "200ms"
-dir = "/cache/d"
[caches.assets]
maxAge = "200ms"
dir = ":resourceDir/_gen"
dir = ":resourceDir/_gen"
`
- for _, name := range []string{filecache.CacheKeyGetCSV, filecache.CacheKeyGetJSON, filecache.CacheKeyAssets, filecache.CacheKeyImages} {
+ for _, name := range []string{filecache.CacheKeyAssets, filecache.CacheKeyImages} {
msg := qt.Commentf("cache: %s", name)
fs := afero.NewMemMapFs()
p := newPathsSpec(t, fs, configStr)
"fmt"
"io"
"strings"
-
- "github.com/gohugoio/hugo/htesting"
"sync"
"testing"
"time"
+ "github.com/gohugoio/hugo/htesting"
+
"github.com/gohugoio/hugo/cache/filecache"
"github.com/gohugoio/hugo/common/hugio"
"github.com/gohugoio/hugo/config"
archeTypedir = "archetypes"
[caches]
-[caches.getJSON]
+[caches.misc]
maxAge = "10h"
dir = ":cacheDir/c"
c.Assert(err, qt.IsNil)
caches.SetResourceFs(p.SourceFs)
- cache := caches.Get("GetJSON")
+ cache := caches.Get("Misc")
c.Assert(cache, qt.Not(qt.IsNil))
cache = caches.Get("Images")
return []byte("bcd"), nil
}
- for _, ca := range []*filecache.Cache{caches.ImageCache(), caches.AssetsCache(), caches.GetJSONCache(), caches.GetCSVCache()} {
+ for _, ca := range []*filecache.Cache{caches.ImageCache(), caches.AssetsCache()} {
for range 2 {
info, r, err := ca.GetOrCreate("a", rf("abc"))
c.Assert(err, qt.IsNil)
}
}
- c.Assert(caches.Get("getJSON"), qt.Not(qt.IsNil))
-
info, w, err := caches.ImageCache().WriteCloser("mykey")
c.Assert(err, qt.IsNil)
c.Assert(info.Name, qt.Equals, "mykey")
archeTypedir = "archetypes"
[caches]
-[caches.getjson]
+[caches.misc]
maxAge = "1s"
dir = "/cache/c"
c.Assert(err, qt.IsNil)
caches.SetResourceFs(p.Fs.Source)
- const cacheName = "getjson"
+ const cacheName = "misc"
filenameData := func(i int) (string, string) {
data := fmt.Sprintf("data: %d", i)
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelError)
// Added just to find the threshold for where we can remove deprecated items.
- // Subtract 5 from the minor version of the first ERRORed version => 0.122.0.
- c.Assert(deprecationLogLevelFromVersion("0.127.0"), qt.Equals, logg.LevelError)
+ // Subtract 5 from the minor version of the first ERRORed version => 0.136.0.
+ c.Assert(deprecationLogLevelFromVersion("0.141.0"), qt.Equals, logg.LevelError)
}
func TestMarkupScope(t *testing.T) {
return err
}
- // Legacy paginate values.
- if c.Paginate != 0 {
- hugo.DeprecateWithLogger("site config key paginate", "Use pagination.pagerSize instead.", "v0.128.0", logger.Logger())
- c.Pagination.PagerSize = c.Paginate
- }
- if c.PaginatePath != "" {
- hugo.DeprecateWithLogger("site config key paginatePath", "Use pagination.path instead.", "v0.128.0", logger.Logger())
- c.Pagination.Path = c.PaginatePath
- }
-
// Legacy privacy values.
if c.Privacy.Twitter.Disable {
hugo.DeprecateWithLogger("site config key privacy.twitter.disable", "Use privacy.x.disable instead.", "v0.141.0", logger.Logger())
// Enable if the site content has CJK language (Chinese, Japanese, or Korean). This affects how Hugo counts words.
HasCJKLanguage bool
- // The default number of pages per page when paginating.
- // Deprecated: Use the Pagination struct.
- Paginate int
-
- // The path to use when creating pagination URLs, e.g. "page" in /page/2/.
- // Deprecated: Use the Pagination struct.
- PaginatePath string
-
// Whether to pluralize default list titles.
// Note that this currently only works for English, but you can provide your own title in the content file's front matter.
PluralizeListTitles bool
return errors.Join(errs...)
}
-func (h *HugoSites) isMultilingual() bool {
- return len(h.Sites) > 1
-}
-
// TODO(bep) consolidate
func (h *HugoSites) LanguageSet() map[string]int {
set := make(map[string]int)
"context"
"github.com/gohugoio/hugo/common/hsync"
- "github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/resources/page"
)
return p.next()
}
-// Deprecated: Use Next instead.
-func (p pagePosition) NextPage() page.Page {
- hugo.Deprecate(".Page.NextPage", "Use .Page.Next instead.", "v0.123.0")
- return p.Next()
-}
-
func (p pagePosition) Prev() page.Page {
return p.prev()
}
-// Deprecated: Use Prev instead.
-func (p pagePosition) PrevPage() page.Page {
- hugo.Deprecate(".Page.PrevPage", "Use .Page.Prev instead.", "v0.123.0")
- return p.Prev()
-}
-
type pagePositionInSection struct {
*nextPrev
}
return s.conf.C.BaseURL.WithPath
}
-// Deprecated: Use .Site.Lastmod instead.
-func (s *Site) LastChange() time.Time {
- s.CheckReady()
- hugo.Deprecate(".Site.LastChange", "Use .Site.Lastmod instead.", "v0.123.0")
- return s.lastmod
-}
-
// Returns the last modification date of the content.
func (s *Site) Lastmod() time.Time {
return s.lastmod
return s.conf.Params
}
-// Deprecated: Use taxonomies instead.
-func (s *Site) Author() map[string]any {
- if len(s.conf.Author) != 0 {
- hugo.Deprecate(".Site.Author", "Implement taxonomy 'author' or use .Site.Params.Author instead.", "v0.124.0")
- }
- return s.conf.Author
-}
-
-// Deprecated: Use taxonomies instead.
-func (s *Site) Authors() page.AuthorList {
- hugo.Deprecate(".Site.Authors", "Implement taxonomy 'authors' or use .Site.Params.Author instead.", "v0.124.0")
- return page.AuthorList{}
-}
-
-// Deprecated: Use .Site.Params instead.
-func (s *Site) Social() map[string]string {
- hugo.Deprecate(".Site.Social", "Implement taxonomy 'social' or use .Site.Params.Social instead.", "v0.124.0")
- return s.conf.Social
-}
-
func (s *Site) Param(key any) (any, error) {
return resource.Param(s, nil, key)
}
return s.conf.BuildDrafts
}
-// Deprecated: Use hugo.IsMultilingual instead.
-func (s *Site) IsMultiLingual() bool {
- hugo.Deprecate(".Site.IsMultiLingual", "Use hugo.IsMultilingual instead.", "v0.124.0")
- return s.h.isMultilingual()
-}
-
func (s *Site) LanguagePrefix() string {
prefix := s.GetLanguagePrefix()
if prefix == "" {
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
- PrevPage() Page
-
- // Deprecated: Use Next. Will be removed in Hugo 0.57
- NextPage() Page
}
// RawContentProvider provides the raw, unprocessed content of the page.
return nil
}
-func (p *nopPage) PrevPage() Page {
- return nil
-}
-
-func (p *nopPage) NextPage() Page {
- return nil
-}
-
func (p *nopPage) RawContent() string {
return ""
}
"math"
"reflect"
- "github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/config"
"github.com/spf13/cast"
return p.pagers
}
-// PageSize returns the size of each paginator page.
-// Deprecated: Use PagerSize instead.
-func (p *Paginator) PageSize() int {
- hugo.Deprecate("PageSize", "Use PagerSize instead.", "v0.128.0")
- return p.size
-}
-
// PagerSize returns the size of each paginator page.
func (p *Paginator) PagerSize() int {
return p.size
// Returns a taxonomy map.
Taxonomies() TaxonomyList
- // Deprecated: Use .Lastmod instead.
- LastChange() time.Time
-
// Returns the last modification date of the content.
Lastmod() time.Time
// Returns the site config.
Config() SiteConfig
- // Deprecated: Use taxonomies instead.
- Author() map[string]any
-
- // Deprecated: Use taxonomies instead.
- Authors() AuthorList
-
- // Deprecated: Use .Site.Params instead.
- Social() map[string]string
-
// BuildDrafts is deprecated and will be removed in a future release.
BuildDrafts() bool
- // Deprecated: Use hugo.IsMultilingual instead.
- IsMultiLingual() bool
-
// LanguagePrefix returns the language prefix for this site.
LanguagePrefix() string
// Sites represents an ordered list of sites (languages).
type Sites []Site
-// Deprecated: Use .Sites.Default instead.
-func (s Sites) First() Site {
- hugo.Deprecate(".Sites.First", "Use .Sites.Default instead.", "v0.127.0")
- return s.Default()
-}
-
// Default is a convenience method to get the site corresponding to the default
// content language.
func (s Sites) Default() Site {
return s.s.Language().Lang
}
-// Deprecated: Use .Site.Params instead.
-func (s *siteWrapper) Social() map[string]string {
- return s.s.Social()
-}
-
-// Deprecated: Use taxonomies instead.
-func (s *siteWrapper) Author() map[string]any {
- return s.s.Author()
-}
-
-// Deprecated: Use taxonomies instead.
-func (s *siteWrapper) Authors() AuthorList {
- return s.s.Authors()
-}
-
func (s *siteWrapper) GetPage(ref ...string) (Page, error) {
return s.s.GetPage(ref...)
}
return s.s.Taxonomies()
}
-// Deprecated: Use .Site.Lastmod instead.
-func (s *siteWrapper) LastChange() time.Time {
- return s.s.LastChange()
-}
-
func (s *siteWrapper) Lastmod() time.Time {
return s.s.Lastmod()
}
return s.s.BuildDrafts()
}
-// Deprecated: Use hugo.IsMultilingual instead.
-func (s *siteWrapper) IsMultiLingual() bool {
- return s.s.IsMultiLingual()
-}
-
func (s *siteWrapper) LanguagePrefix() string {
return s.s.LanguagePrefix()
}
l *langs.Language
}
-// Deprecated: Use taxonomies instead.
-func (s testSite) Author() map[string]any {
- return nil
-}
-
-// Deprecated: Use taxonomies instead.
-func (s testSite) Authors() AuthorList {
- return AuthorList{}
-}
-
-// Deprecated: Use .Site.Params instead.
-func (s testSite) Social() map[string]string {
- return make(map[string]string)
-}
-
func (t testSite) Hugo() hugo.HugoInfo {
return t.h
}
return 1313
}
-// Deprecated: Use .Site.Lastmod instead.
-func (testSite) LastChange() (t time.Time) {
- return
-}
-
func (testSite) Lastmod() (t time.Time) {
return
}
return false
}
-// Deprecated: Use hugo.IsMultilingual instead.
-func (s testSite) IsMultiLingual() bool {
- return false
-}
-
func (s testSite) Param(key any) (any, error) {
return nil, nil
}
"encoding/hex"
"fmt"
"hash"
- "hash/fnv"
- "github.com/gohugoio/hugo/common/hugo"
"github.com/spf13/cast"
)
return hex.EncodeToString(hash[:]), nil
}
-// FNV32a hashes v using fnv32a algorithm.
-// <docsmeta>{"newIn": "0.98.0" }</docsmeta>
-func (ns *Namespace) FNV32a(v any) (int, error) {
- hugo.Deprecate("crypto.FNV32a", "Use hash.FNV32a.", "v0.129.0")
- conv, err := cast.ToStringE(v)
- if err != nil {
- return 0, err
- }
- algorithm := fnv.New32a()
- algorithm.Write([]byte(conv))
- return int(algorithm.Sum32()), nil
-}
-
// HMAC returns a cryptographic hash that uses a key to sign a message.
func (ns *Namespace) HMAC(h any, k any, m any, e ...any) (string, error) {
ha, err := cast.ToStringE(h)
Context: func(cctx context.Context, args ...any) (any, error) { return ctx, nil },
}
- // Deprecated. Use hash.FNV32a instead.
- ns.AddMethodMapping(ctx.FNV32a,
- nil,
- [][2]string{},
- )
-
ns.AddMethodMapping(ctx.HMAC,
[]string{"hmac"},
[][2]string{
+++ /dev/null
-// Copyright 2017 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 data provides template functions for working with external data
-// sources.
-package data
-
-import (
- "bytes"
- "encoding/csv"
- "encoding/json"
- "errors"
- "fmt"
- "net/http"
- "slices"
- "strings"
-
- "github.com/gohugoio/hugo/cache/filecache"
- "github.com/gohugoio/hugo/common/hmaps"
- "github.com/gohugoio/hugo/common/hugo"
- "github.com/gohugoio/hugo/config/security"
-
- "github.com/gohugoio/hugo/common/types"
-
- "github.com/gohugoio/hugo/common/constants"
-
- "github.com/spf13/cast"
-
- "github.com/gohugoio/hugo/deps"
-)
-
-// New returns a new instance of the data-namespaced template functions.
-func New(deps *deps.Deps) *Namespace {
- return &Namespace{
- deps: deps,
- cacheGetCSV: deps.ResourceSpec.FileCaches.GetCSVCache(),
- cacheGetJSON: deps.ResourceSpec.FileCaches.GetJSONCache(),
- client: http.DefaultClient,
- }
-}
-
-// Namespace provides template functions for the "data" namespace.
-type Namespace struct {
- deps *deps.Deps
-
- cacheGetJSON *filecache.Cache
- cacheGetCSV *filecache.Cache
-
- client *http.Client
-}
-
-// GetCSV expects the separator sep and one or n-parts of a URL to a resource which
-// can either be a local or a remote one.
-// The data separator can be a comma, semi-colon, pipe, etc, but only one character.
-// If you provide multiple parts for the URL they will be joined together to the final URL.
-// GetCSV returns nil or a slice slice to use in a short code.
-func (ns *Namespace) GetCSV(sep string, args ...any) (d [][]string, err error) {
- hugo.Deprecate("data.GetCSV", "use resources.Get or resources.GetRemote with transform.Unmarshal.", "v0.123.0")
-
- url, headers := toURLAndHeaders(args)
- cache := ns.cacheGetCSV
-
- unmarshal := func(b []byte) (bool, error) {
- if d, err = parseCSV(b, sep); err != nil {
- err = fmt.Errorf("failed to parse CSV file %s: %w", url, err)
-
- return true, err
- }
-
- return false, nil
- }
-
- var req *http.Request
- req, err = http.NewRequest("GET", url, nil)
- if err != nil {
- return nil, fmt.Errorf("failed to create request for getCSV for resource %s: %w", url, err)
- }
-
- // Add custom user headers.
- addUserProvidedHeaders(headers, req)
- addDefaultHeaders(req, "text/csv", "text/plain")
-
- err = ns.getResource(cache, unmarshal, req)
- if err != nil {
- if security.IsAccessDenied(err) {
- return nil, err
- }
- ns.deps.Log.Erroridf(constants.ErrRemoteGetCSV, "Failed to get CSV resource %q: %s", url, err)
- return nil, nil
- }
-
- return
-}
-
-// GetJSON expects one or n-parts of a URL in args to a resource which can either be a local or a remote one.
-// If you provide multiple parts they will be joined together to the final URL.
-// GetJSON returns nil or parsed JSON to use in a short code.
-func (ns *Namespace) GetJSON(args ...any) (any, error) {
- hugo.Deprecate("data.GetJSON", "use resources.Get or resources.GetRemote with transform.Unmarshal.", "v0.123.0")
-
- var v any
- url, headers := toURLAndHeaders(args)
- cache := ns.cacheGetJSON
-
- req, err := http.NewRequest("GET", url, nil)
- if err != nil {
- return nil, fmt.Errorf("failed to create request for getJSON resource %s: %w", url, err)
- }
-
- unmarshal := func(b []byte) (bool, error) {
- err := json.Unmarshal(b, &v)
- if err != nil {
- return true, err
- }
- return false, nil
- }
-
- addUserProvidedHeaders(headers, req)
- addDefaultHeaders(req, "application/json")
-
- err = ns.getResource(cache, unmarshal, req)
- if err != nil {
- if security.IsAccessDenied(err) {
- return nil, err
- }
- ns.deps.Log.Erroridf(constants.ErrRemoteGetJSON, "Failed to get JSON resource %q: %s", url, err)
- return nil, nil
- }
-
- return v, nil
-}
-
-func addDefaultHeaders(req *http.Request, accepts ...string) {
- for _, accept := range accepts {
- if !hasHeaderValue(req.Header, "Accept", accept) {
- req.Header.Add("Accept", accept)
- }
- }
- if !hasHeaderKey(req.Header, "User-Agent") {
- req.Header.Add("User-Agent", "Hugo Static Site Generator")
- }
-}
-
-func addUserProvidedHeaders(headers map[string]any, req *http.Request) {
- if headers == nil {
- return
- }
- for key, val := range headers {
- vals := types.ToStringSlicePreserveString(val)
- for _, s := range vals {
- req.Header.Add(key, s)
- }
- }
-}
-
-func hasHeaderValue(m http.Header, key, value string) bool {
- var s []string
- var ok bool
-
- if s, ok = m[key]; !ok {
- return false
- }
-
- return slices.Contains(s, value)
-}
-
-func hasHeaderKey(m http.Header, key string) bool {
- _, ok := m[key]
- return ok
-}
-
-func toURLAndHeaders(urlParts []any) (string, map[string]any) {
- if len(urlParts) == 0 {
- return "", nil
- }
-
- // The last argument may be a map.
- headers, err := hmaps.ToStringMapE(urlParts[len(urlParts)-1])
- if err == nil {
- urlParts = urlParts[:len(urlParts)-1]
- } else {
- headers = nil
- }
-
- return strings.Join(cast.ToStringSlice(urlParts), ""), headers
-}
-
-// parseCSV parses bytes of CSV data into a slice slice string or an error
-func parseCSV(c []byte, sep string) ([][]string, error) {
- if len(sep) != 1 {
- return nil, errors.New("Incorrect length of CSV separator: " + sep)
- }
- b := bytes.NewReader(c)
- r := csv.NewReader(b)
- rSep := []rune(sep)
- r.Comma = rSep[0]
- r.FieldsPerRecord = 0
- return r.ReadAll()
-}
+++ /dev/null
-// Copyright 2017 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 data
-
-import (
- "bytes"
- "html/template"
- "net/http"
- "net/http/httptest"
- "path/filepath"
- "strings"
- "testing"
-
- "github.com/bep/logg"
- "github.com/gohugoio/hugo/common/hmaps"
- "github.com/gohugoio/hugo/htesting"
-
- qt "github.com/frankban/quicktest"
-)
-
-func TestGetCSV(t *testing.T) {
- t.Parallel()
- htesting.SkipSlowTestUnlessCI(t)
-
- c := qt.New(t)
-
- for i, test := range []struct {
- sep string
- url string
- content string
- expect any
- }{
- // Remotes
- {
- ",",
- `http://success/`,
- "gomeetup,city\nyes,Sydney\nyes,San Francisco\nyes,Stockholm\n",
- [][]string{{"gomeetup", "city"}, {"yes", "Sydney"}, {"yes", "San Francisco"}, {"yes", "Stockholm"}},
- },
- {
- ",",
- `http://error.extra.field/`,
- "gomeetup,city\nyes,Sydney\nyes,San Francisco\nyes,Stockholm,EXTRA\n",
- false,
- },
- {
- ",",
- `http://nofound/404`,
- ``,
- false,
- },
-
- // Locals
- {
- ";",
- "pass/semi",
- "gomeetup;city\nyes;Sydney\nyes;San Francisco\nyes;Stockholm\n",
- [][]string{{"gomeetup", "city"}, {"yes", "Sydney"}, {"yes", "San Francisco"}, {"yes", "Stockholm"}},
- },
- {
- ";",
- "fail/no-file",
- "",
- false,
- },
- } {
- c.Run(test.url, func(c *qt.C) {
- msg := qt.Commentf("Test %d", i)
-
- ns := newTestNs()
-
- // Setup HTTP test server
- var srv *httptest.Server
- srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) {
- if !hasHeaderValue(r.Header, "Accept", "text/csv") && !hasHeaderValue(r.Header, "Accept", "text/plain") {
- http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
- return
- }
-
- if r.URL.Path == "/404" {
- http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
- return
- }
-
- w.Header().Add("Content-type", "text/csv")
-
- w.Write([]byte(test.content))
- })
- defer func() { srv.Close() }()
-
- // Setup local test file for schema-less URLs
- if !strings.Contains(test.url, ":") && !strings.HasPrefix(test.url, "fail/") {
- f, err := ns.deps.Fs.Source.Create(filepath.Join(ns.deps.Conf.BaseConfig().WorkingDir, test.url))
- c.Assert(err, qt.IsNil, msg)
- f.WriteString(test.content)
- f.Close()
- }
-
- // Get on with it
- got, err := ns.GetCSV(test.sep, test.url)
-
- if _, ok := test.expect.(bool); ok {
- c.Assert(int(ns.deps.Log.LoggCount(logg.LevelError)), qt.Equals, 1)
- c.Assert(got, qt.IsNil)
- return
- }
-
- c.Assert(err, qt.IsNil, msg)
- c.Assert(int(ns.deps.Log.LoggCount(logg.LevelError)), qt.Equals, 0)
- c.Assert(got, qt.Not(qt.IsNil), msg)
- c.Assert(got, qt.DeepEquals, test.expect, msg)
- })
- }
-}
-
-func TestGetJSON(t *testing.T) {
- t.Parallel()
- htesting.SkipSlowTestUnlessCI(t)
- c := qt.New(t)
-
- for i, test := range []struct {
- url string
- content string
- expect any
- }{
- {
- `http://success/`,
- `{"gomeetup":["Sydney","San Francisco","Stockholm"]}`,
- map[string]any{"gomeetup": []any{"Sydney", "San Francisco", "Stockholm"}},
- },
- {
- `http://malformed/`,
- `{gomeetup:["Sydney","San Francisco","Stockholm"]}`,
- false,
- },
- {
- `http://nofound/404`,
- ``,
- false,
- },
- // Locals
- {
- "pass/semi",
- `{"gomeetup":["Sydney","San Francisco","Stockholm"]}`,
- map[string]any{"gomeetup": []any{"Sydney", "San Francisco", "Stockholm"}},
- },
- {
- "fail/no-file",
- "",
- false,
- },
- {
- `pass/üńīçøðê-url.json`,
- `{"gomeetup":["Sydney","San Francisco","Stockholm"]}`,
- map[string]any{"gomeetup": []any{"Sydney", "San Francisco", "Stockholm"}},
- },
- } {
- c.Run(test.url, func(c *qt.C) {
- msg := qt.Commentf("Test %d", i)
- ns := newTestNs()
-
- // Setup HTTP test server
- var srv *httptest.Server
- srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) {
- if !hasHeaderValue(r.Header, "Accept", "application/json") {
- http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
- return
- }
-
- if r.URL.Path == "/404" {
- http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
- return
- }
-
- w.Header().Add("Content-type", "application/json")
-
- w.Write([]byte(test.content))
- })
- defer func() { srv.Close() }()
-
- // Setup local test file for schema-less URLs
- if !strings.Contains(test.url, ":") && !strings.HasPrefix(test.url, "fail/") {
- f, err := ns.deps.Fs.Source.Create(filepath.Join(ns.deps.Conf.BaseConfig().WorkingDir, test.url))
- c.Assert(err, qt.IsNil, msg)
- f.WriteString(test.content)
- f.Close()
- }
-
- // Get on with it
- got, _ := ns.GetJSON(test.url)
-
- if _, ok := test.expect.(bool); ok {
- c.Assert(int(ns.deps.Log.LoggCount(logg.LevelError)), qt.Equals, 1)
- return
- }
-
- c.Assert(int(ns.deps.Log.LoggCount(logg.LevelError)), qt.Equals, 0, msg)
- c.Assert(got, qt.Not(qt.IsNil), msg)
- c.Assert(got, qt.DeepEquals, test.expect)
- })
- }
-}
-
-func TestHeaders(t *testing.T) {
- t.Parallel()
- c := qt.New(t)
-
- for _, test := range []struct {
- name string
- headers any
- assert func(c *qt.C, headers string)
- }{
- {
- `Misc header variants`,
- map[string]any{
- "Accept-Charset": "utf-8",
- "Max-forwards": "10",
- "X-Int": 32,
- "X-Templ": template.HTML("a"),
- "X-Multiple": []string{"a", "b"},
- "X-MultipleInt": []int{3, 4},
- },
- func(c *qt.C, headers string) {
- c.Assert(headers, qt.Contains, "Accept-Charset: utf-8")
- c.Assert(headers, qt.Contains, "Max-Forwards: 10")
- c.Assert(headers, qt.Contains, "X-Int: 32")
- c.Assert(headers, qt.Contains, "X-Templ: a")
- c.Assert(headers, qt.Contains, "X-Multiple: a")
- c.Assert(headers, qt.Contains, "X-Multiple: b")
- c.Assert(headers, qt.Contains, "X-Multipleint: 3")
- c.Assert(headers, qt.Contains, "X-Multipleint: 4")
- c.Assert(headers, qt.Contains, "User-Agent: Hugo Static Site Generator")
- },
- },
- {
- `Params`,
- hmaps.Params{
- "Accept-Charset": "utf-8",
- },
- func(c *qt.C, headers string) {
- c.Assert(headers, qt.Contains, "Accept-Charset: utf-8")
- },
- },
- {
- `Override User-Agent`,
- map[string]any{
- "User-Agent": "007",
- },
- func(c *qt.C, headers string) {
- c.Assert(headers, qt.Contains, "User-Agent: 007")
- },
- },
- } {
- c.Run(test.name, func(c *qt.C) {
- ns := newTestNs()
-
- // Setup HTTP test server
- var srv *httptest.Server
- var headers bytes.Buffer
- srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) {
- c.Assert(r.URL.String(), qt.Equals, "http://gohugo.io/api?foo")
- w.Write([]byte("{}"))
- r.Header.Write(&headers)
- })
- defer func() { srv.Close() }()
-
- testFunc := func(fn func(args ...any) error) {
- defer headers.Reset()
- err := fn("http://example.org/api", "?foo", test.headers)
-
- c.Assert(err, qt.IsNil)
- c.Assert(int(ns.deps.Log.LoggCount(logg.LevelError)), qt.Equals, 0)
- test.assert(c, headers.String())
- }
-
- testFunc(func(args ...any) error {
- _, err := ns.GetJSON(args...)
- return err
- })
- testFunc(func(args ...any) error {
- _, err := ns.GetCSV(",", args...)
- return err
- })
- })
- }
-}
-
-func TestToURLAndHeaders(t *testing.T) {
- t.Parallel()
- c := qt.New(t)
- url, headers := toURLAndHeaders([]any{"https://foo?id=", 32})
- c.Assert(url, qt.Equals, "https://foo?id=32")
- c.Assert(headers, qt.IsNil)
-
- url, headers = toURLAndHeaders([]any{"https://foo?id=", 32, map[string]any{"a": "b"}})
- c.Assert(url, qt.Equals, "https://foo?id=32")
- c.Assert(headers, qt.DeepEquals, map[string]any{"a": "b"})
-}
-
-func TestParseCSV(t *testing.T) {
- t.Parallel()
- c := qt.New(t)
-
- for i, test := range []struct {
- csv []byte
- sep string
- exp string
- err bool
- }{
- {[]byte("a,b,c\nd,e,f\n"), "", "", true},
- {[]byte("a,b,c\nd,e,f\n"), "~/", "", true},
- {[]byte("a,b,c\nd,e,f"), "|", "a,b,cd,e,f", false},
- {[]byte("q,w,e\nd,e,f"), ",", "qwedef", false},
- {[]byte("a|b|c\nd|e|f|g"), "|", "abcdefg", true},
- {[]byte("z|y|c\nd|e|f"), "|", "zycdef", false},
- } {
- msg := qt.Commentf("Test %d: %v", i, test)
-
- csv, err := parseCSV(test.csv, test.sep)
- if test.err {
- c.Assert(err, qt.Not(qt.IsNil), msg)
- continue
- }
- c.Assert(err, qt.IsNil, msg)
-
- act := ""
- for _, v := range csv {
- act = act + strings.Join(v, "")
- }
-
- c.Assert(act, qt.Equals, test.exp, msg)
- }
-}
+++ /dev/null
-// Copyright 2017 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 data
-
-import (
- "context"
-
- "github.com/gohugoio/hugo/deps"
- "github.com/gohugoio/hugo/tpl/internal"
-)
-
-const name = "data"
-
-func init() {
- f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
- ctx := New(d)
-
- ns := &internal.TemplateFuncsNamespace{
- Name: name,
- Context: func(cctx context.Context, args ...any) (any, error) { return ctx, nil },
- }
-
- // Deprecated. Use resources.GetRemote instead.
- ns.AddMethodMapping(ctx.GetCSV,
- []string{"getCSV"},
- [][2]string{},
- )
-
- // Deprecated. Use resources.GetRemote instead.
- ns.AddMethodMapping(ctx.GetJSON,
- []string{"getJSON"},
- [][2]string{},
- )
- return ns
- }
-
- internal.AddTemplateFuncsNamespace(f)
-}
+++ /dev/null
-// Copyright 2016 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 data
-
-import (
- "bytes"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "path/filepath"
- "time"
-
- "github.com/gohugoio/hugo/cache/filecache"
- "github.com/gohugoio/hugo/common/hashing"
- "github.com/spf13/afero"
-)
-
-var (
- resSleep = time.Second * 2 // if JSON decoding failed sleep for n seconds before retrying
- resRetries = 1 // number of retries to load the JSON from URL
-)
-
-// getRemote loads the content of a remote file. This method is thread safe.
-func (ns *Namespace) getRemote(cache *filecache.Cache, unmarshal func([]byte) (bool, error), req *http.Request) error {
- url := req.URL.String()
- if err := ns.deps.ExecHelper.Sec().CheckAllowedHTTPURL(url); err != nil {
- return err
- }
- if err := ns.deps.ExecHelper.Sec().CheckAllowedHTTPMethod("GET"); err != nil {
- return err
- }
-
- var headers bytes.Buffer
- req.Header.Write(&headers)
- id := hashing.MD5FromStringHexEncoded(url + headers.String())
- var handled bool
- var retry bool
-
- _, b, err := cache.GetOrCreateBytes(id, func() ([]byte, error) {
- var err error
- handled = true
- for i := 0; i <= resRetries; i++ {
- ns.deps.Log.Infof("Downloading: %s ...", url)
- var res *http.Response
- res, err = ns.client.Do(req)
- if err != nil {
- return nil, err
- }
-
- var b []byte
- b, err = io.ReadAll(res.Body)
- if err != nil {
- return nil, err
- }
- res.Body.Close()
-
- if isHTTPError(res) {
- return nil, fmt.Errorf("failed to retrieve remote file: %s, body: %q", http.StatusText(res.StatusCode), b)
- }
-
- retry, err = unmarshal(b)
-
- if err == nil {
- // Return it so it can be cached.
- return b, nil
- }
-
- if !retry {
- return nil, err
- }
-
- ns.deps.Log.Infof("Cannot read remote resource %s: %s", url, err)
- ns.deps.Log.Infof("Retry #%d for %s and sleeping for %s", i+1, url, resSleep)
- time.Sleep(resSleep)
- }
-
- return nil, err
- })
-
- if !handled {
- // This is cached content and should be correct.
- _, err = unmarshal(b)
- }
-
- return err
-}
-
-// getLocal loads the content of a local file
-func getLocal(workingDir, url string, fs afero.Fs) ([]byte, error) {
- filename := filepath.Join(workingDir, url)
- return afero.ReadFile(fs, filename)
-}
-
-// getResource loads the content of a local or remote file and returns its content and the
-// cache ID used, if relevant.
-func (ns *Namespace) getResource(cache *filecache.Cache, unmarshal func(b []byte) (bool, error), req *http.Request) error {
- switch req.URL.Scheme {
- case "":
- url, err := url.QueryUnescape(req.URL.String())
- if err != nil {
- return err
- }
- b, err := getLocal(ns.deps.Conf.BaseConfig().WorkingDir, url, ns.deps.Fs.Source)
- if err != nil {
- return err
- }
- _, err = unmarshal(b)
- return err
- default:
- return ns.getRemote(cache, unmarshal, req)
- }
-}
-
-func isHTTPError(res *http.Response) bool {
- return res.StatusCode < 200 || res.StatusCode > 299
-}
+++ /dev/null
-// Copyright 2016 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 data
-
-import (
- "bytes"
- "net/http"
- "net/http/httptest"
- "net/url"
- "path/filepath"
- "sync"
- "testing"
- "time"
-
- "github.com/gohugoio/hugo/cache/filecache"
- "github.com/gohugoio/hugo/common/loggers"
-
- "github.com/gohugoio/hugo/config/testconfig"
-
- "github.com/gohugoio/hugo/helpers"
-
- qt "github.com/frankban/quicktest"
- "github.com/gohugoio/hugo/config"
- "github.com/gohugoio/hugo/deps"
- "github.com/gohugoio/hugo/hugofs"
- "github.com/spf13/afero"
-)
-
-func TestScpGetLocal(t *testing.T) {
- t.Parallel()
- v := config.New()
- workingDir := "/my/working/dir"
- v.Set("workingDir", workingDir)
- v.Set("publishDir", "public")
- fs := hugofs.NewFromOld(afero.NewMemMapFs(), v)
- ps := helpers.FilePathSeparator
-
- tests := []struct {
- path string
- content []byte
- }{
- {"testpath" + ps + "test.txt", []byte(`T€st Content 123 fOO,bar:foo%bAR`)},
- {"FOo" + ps + "BaR.html", []byte(`FOo/BaR.html T€st Content 123`)},
- {"трям" + ps + "трям", []byte(`T€st трям/трям Content 123`)},
- {"은행", []byte(`T€st C은행ontent 123`)},
- {"Банковский кассир", []byte(`Банковский кассир T€st Content 123`)},
- }
-
- for _, test := range tests {
- r := bytes.NewReader(test.content)
- err := helpers.WriteToDisk(filepath.Join(workingDir, test.path), r, fs.Source)
- if err != nil {
- t.Error(err)
- }
-
- c, err := getLocal(workingDir, test.path, fs.Source)
- if err != nil {
- t.Errorf("Error getting resource content: %s", err)
- }
- if !bytes.Equal(c, test.content) {
- t.Errorf("\nExpected: %s\nActual: %s\n", string(test.content), string(c))
- }
- }
-}
-
-func getTestServer(handler func(w http.ResponseWriter, r *http.Request)) (*httptest.Server, *http.Client) {
- testServer := httptest.NewServer(http.HandlerFunc(handler))
- client := &http.Client{
- Transport: &http.Transport{Proxy: func(r *http.Request) (*url.URL, error) {
- // Remove when https://github.com/golang/go/issues/13686 is fixed
- r.Host = "gohugo.io"
- return url.Parse(testServer.URL)
- }},
- }
- return testServer, client
-}
-
-func TestScpGetRemote(t *testing.T) {
- t.Parallel()
- c := qt.New(t)
- fs := new(afero.MemMapFs)
- cache := filecache.NewCache(fs, 100, "")
-
- tests := []struct {
- path string
- content []byte
- }{
- {"http://Foo.Bar/foo_Bar-Foo", []byte(`T€st Content 123`)},
- {"http://Doppel.Gänger/foo_Bar-Foo", []byte(`T€st Cont€nt 123`)},
- {"http://Doppel.Gänger/Fizz_Bazz-Foo", []byte(`T€st Банковский кассир Cont€nt 123`)},
- {"http://Doppel.Gänger/Fizz_Bazz-Bar", []byte(`T€st Банковский кассир Cont€nt 456`)},
- }
-
- for _, test := range tests {
- msg := qt.Commentf("%v", test)
-
- req, err := http.NewRequest("GET", test.path, nil)
- c.Assert(err, qt.IsNil, msg)
-
- srv, cl := getTestServer(func(w http.ResponseWriter, r *http.Request) {
- w.Write(test.content)
- })
- defer func() { srv.Close() }()
-
- ns := newTestNs()
- ns.client = cl
-
- var cb []byte
- f := func(b []byte) (bool, error) {
- cb = b
- return false, nil
- }
-
- err = ns.getRemote(cache, f, req)
- c.Assert(err, qt.IsNil, msg)
- c.Assert(string(cb), qt.Equals, string(test.content))
-
- c.Assert(string(cb), qt.Equals, string(test.content))
-
- }
-}
-
-func TestScpGetRemoteParallel(t *testing.T) {
- t.Parallel()
- c := qt.New(t)
-
- content := []byte(`T€st Content 123`)
- srv, cl := getTestServer(func(w http.ResponseWriter, r *http.Request) {
- w.Write(content)
- })
-
- defer func() { srv.Close() }()
-
- url := "http://Foo.Bar/foo_Bar-Foo"
- req, err := http.NewRequest("GET", url, nil)
- c.Assert(err, qt.IsNil)
-
- for _, ignoreCache := range []bool{false} {
- cfg := config.New()
- cfg.Set("ignoreCache", ignoreCache)
-
- ns := New(newDeps(cfg))
- ns.client = cl
-
- var wg sync.WaitGroup
-
- for i := range 1 {
- wg.Add(1)
- go func(gor int) {
- defer wg.Done()
- for range 10 {
- var cb []byte
- f := func(b []byte) (bool, error) {
- cb = b
- return false, nil
- }
- err := ns.getRemote(ns.cacheGetJSON, f, req)
-
- c.Assert(err, qt.IsNil)
- if string(content) != string(cb) {
- t.Errorf("expected\n%q\ngot\n%q", content, cb)
- }
-
- time.Sleep(23 * time.Millisecond)
- }
- }(i)
- }
-
- wg.Wait()
- }
-}
-
-func newDeps(cfg config.Provider) *deps.Deps {
- conf := testconfig.GetTestConfig(nil, cfg)
- logger := loggers.NewDefault()
- fs := hugofs.NewFrom(afero.NewMemMapFs(), conf.BaseConfig())
-
- d := &deps.Deps{
- Fs: fs,
- Log: logger,
- Conf: conf,
- }
- if err := d.Init(); err != nil {
- panic(err)
- }
- return d
-}
-
-func newTestNs() *Namespace {
- return New(newDeps(config.New()))
-}
"context"
"github.com/gohugoio/hugo/deps"
- "github.com/gohugoio/hugo/tpl/css"
"github.com/gohugoio/hugo/tpl/internal"
- "github.com/gohugoio/hugo/tpl/js"
)
const name = "resources"
ns := &internal.TemplateFuncsNamespace{
Name: name,
Context: func(cctx context.Context, args ...any) (any, error) { return ctx, nil },
- OnCreated: func(m map[string]any) {
- for _, v := range m {
- switch v := v.(type) {
- case *css.Namespace:
- ctx.cssNs = v
- case *js.Namespace:
- ctx.jsNs = v
- }
- }
- if ctx.cssNs == nil {
- panic("css namespace not found")
- }
- if ctx.jsNs == nil {
- panic("js namespace not found")
- }
- },
}
- // Deprecated. Use js.Babel instead.
- ns.AddMethodMapping(ctx.Babel,
- nil,
- [][2]string{},
- )
-
ns.AddMethodMapping(ctx.ByType,
nil,
[][2]string{},
[][2]string{},
)
- // Deprecated. Use css.PostCSS instead.
- ns.AddMethodMapping(ctx.PostCSS,
- nil,
- [][2]string{},
- )
-
ns.AddMethodMapping(ctx.PostProcess,
nil,
[][2]string{},
)
- // Deprecated. Use css.Sass instead.
- ns.AddMethodMapping(ctx.ToCSS,
- nil,
- [][2]string{},
- )
-
return ns
}
"fmt"
"github.com/gohugoio/hugo/common/hmaps"
- "github.com/gohugoio/hugo/common/hugo"
-
- "github.com/gohugoio/hugo/tpl/css"
- "github.com/gohugoio/hugo/tpl/js"
"github.com/gohugoio/hugo/resources/postpub"
integrityClient *integrity.Client
minifyClient *minifier.Client
templatesClient *templates.Client
-
- // We moved some CSS and JS related functions to the css and js package in Hugo 0.128.0.
- // Keep this here until the deprecation period is over.
- cssNs *css.Namespace
- jsNs *js.Namespace
}
// Copy copies r to the new targetPath in s.
return ns.minifyClient.Minify(r)
}
-// ToCSS converts the given Resource to CSS. You can optional provide an Options object
-// as second argument. As an option, you can e.g. specify e.g. the target path (string)
-// for the converted CSS resource.
-// Deprecated: Moved to the css namespace in Hugo 0.128.0.
-func (ns *Namespace) ToCSS(args ...any) (resource.Resource, error) {
- hugo.Deprecate("resources.ToCSS", "Use css.Sass instead.", "v0.128.0")
- return ns.cssNs.Sass(args...)
-}
-
-// PostCSS processes the given Resource with PostCSS.
-// Deprecated: Moved to the css namespace in Hugo 0.128.0.
-func (ns *Namespace) PostCSS(args ...any) (resource.Resource, error) {
- hugo.Deprecate("resources.PostCSS", "Use css.PostCSS instead.", "v0.128.0")
- return ns.cssNs.PostCSS(args...)
-}
-
// PostProcess processes r after the build.
func (ns *Namespace) PostProcess(r resource.Resource) (postpub.PostPublishedResource, error) {
return ns.deps.ResourceSpec.PostProcess(r)
}
-
-// Babel processes the given Resource with Babel.
-// Deprecated: Moved to the js namespace in Hugo 0.128.0.
-func (ns *Namespace) Babel(args ...any) (resource.Resource, error) {
- hugo.Deprecate("resources.Babel", "Use js.Babel.", "v0.128.0")
- return ns.jsNs.Babel(args...)
-}
_ "github.com/gohugoio/hugo/tpl/compare"
_ "github.com/gohugoio/hugo/tpl/crypto"
_ "github.com/gohugoio/hugo/tpl/css"
- _ "github.com/gohugoio/hugo/tpl/data"
_ "github.com/gohugoio/hugo/tpl/debug"
_ "github.com/gohugoio/hugo/tpl/diagrams"
_ "github.com/gohugoio/hugo/tpl/encoding"