|
|
|
@@ -114,17 +114,18 @@ func NewStore(opts StoreOptions, siteOpts SiteOptions) (*TemplateStore, error) {
|
|
|
|
|
panic("HTML output format not found")
|
|
|
|
|
}
|
|
|
|
|
s := &TemplateStore{
|
|
|
|
|
opts: opts,
|
|
|
|
|
siteOpts: siteOpts,
|
|
|
|
|
optsOrig: opts,
|
|
|
|
|
siteOptsOrig: siteOpts,
|
|
|
|
|
htmlFormat: html,
|
|
|
|
|
storeSite: configureSiteStorage(siteOpts, opts.Watching),
|
|
|
|
|
treeMain: doctree.NewSimpleTree[map[nodeKey]*TemplInfo](),
|
|
|
|
|
treeShortcodes: doctree.NewSimpleTree[map[string]map[TemplateDescriptor]*TemplInfo](),
|
|
|
|
|
templatesByPath: maps.NewCache[string, *TemplInfo](),
|
|
|
|
|
shortcodesByName: maps.NewCache[string, *TemplInfo](),
|
|
|
|
|
cacheLookupPartials: maps.NewCache[string, *TemplInfo](),
|
|
|
|
|
opts: opts,
|
|
|
|
|
siteOpts: siteOpts,
|
|
|
|
|
optsOrig: opts,
|
|
|
|
|
siteOptsOrig: siteOpts,
|
|
|
|
|
htmlFormat: html,
|
|
|
|
|
storeSite: configureSiteStorage(siteOpts, opts.Watching),
|
|
|
|
|
treeMain: doctree.NewSimpleTree[map[nodeKey]*TemplInfo](),
|
|
|
|
|
treeShortcodes: doctree.NewSimpleTree[map[string]map[TemplateDescriptor]*TemplInfo](),
|
|
|
|
|
templatesByPath: maps.NewCache[string, *TemplInfo](),
|
|
|
|
|
shortcodesByName: maps.NewCache[string, *TemplInfo](),
|
|
|
|
|
cacheLookupPartials: maps.NewCache[string, *TemplInfo](),
|
|
|
|
|
templatesSnapshotSet: maps.NewCache[*parse.Tree, struct{}](),
|
|
|
|
|
|
|
|
|
|
// Note that the funcs passed below is just for name validation.
|
|
|
|
|
tns: newTemplateNamespace(siteOpts.TemplateFuncs),
|
|
|
|
@@ -143,10 +144,10 @@ func NewStore(opts StoreOptions, siteOpts SiteOptions) (*TemplateStore, error) {
|
|
|
|
|
if err := s.insertEmbedded(); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if err := s.parseTemplates(); err != nil {
|
|
|
|
|
if err := s.parseTemplates(false); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if err := s.extractInlinePartials(); err != nil {
|
|
|
|
|
if err := s.extractInlinePartials(false); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if err := s.transformTemplates(); err != nil {
|
|
|
|
@@ -424,10 +425,11 @@ type TemplateStore struct {
|
|
|
|
|
siteOpts SiteOptions
|
|
|
|
|
htmlFormat output.Format
|
|
|
|
|
|
|
|
|
|
treeMain *doctree.SimpleTree[map[nodeKey]*TemplInfo]
|
|
|
|
|
treeShortcodes *doctree.SimpleTree[map[string]map[TemplateDescriptor]*TemplInfo]
|
|
|
|
|
templatesByPath *maps.Cache[string, *TemplInfo]
|
|
|
|
|
shortcodesByName *maps.Cache[string, *TemplInfo]
|
|
|
|
|
treeMain *doctree.SimpleTree[map[nodeKey]*TemplInfo]
|
|
|
|
|
treeShortcodes *doctree.SimpleTree[map[string]map[TemplateDescriptor]*TemplInfo]
|
|
|
|
|
templatesByPath *maps.Cache[string, *TemplInfo]
|
|
|
|
|
shortcodesByName *maps.Cache[string, *TemplInfo]
|
|
|
|
|
templatesSnapshotSet *maps.Cache[*parse.Tree, struct{}]
|
|
|
|
|
|
|
|
|
|
dh descriptorHandler
|
|
|
|
|
|
|
|
|
@@ -709,12 +711,16 @@ func (s *TemplateStore) RefreshFiles(include func(fi hugofs.FileMetaInfo) bool)
|
|
|
|
|
if err := s.insertTemplates(include, true); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err := s.parseTemplates(); err != nil {
|
|
|
|
|
if err := s.createTemplatesSnapshot(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err := s.extractInlinePartials(); err != nil {
|
|
|
|
|
if err := s.parseTemplates(true); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err := s.extractInlinePartials(true); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := s.transformTemplates(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
@@ -940,59 +946,77 @@ func (s *TemplateStore) extractIdentifiers(line string) []string {
|
|
|
|
|
return identifiers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *TemplateStore) extractInlinePartials() error {
|
|
|
|
|
func (s *TemplateStore) extractInlinePartials(rebuild bool) error {
|
|
|
|
|
isPartialName := func(s string) bool {
|
|
|
|
|
return strings.HasPrefix(s, "partials/") || strings.HasPrefix(s, "_partials/")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p := s.tns
|
|
|
|
|
// We may find both inline and external partials in the current template namespaces,
|
|
|
|
|
// so only add the ones we have not seen before.
|
|
|
|
|
addIfNotSeen := func(isText bool, templs ...tpl.Template) error {
|
|
|
|
|
for _, templ := range templs {
|
|
|
|
|
if templ.Name() == "" || !isPartialName(templ.Name()) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
name := templ.Name()
|
|
|
|
|
if !paths.HasExt(name) {
|
|
|
|
|
// Assume HTML. This in line with how the lookup works.
|
|
|
|
|
name = name + s.htmlFormat.MediaType.FirstSuffix.FullSuffix
|
|
|
|
|
}
|
|
|
|
|
if !strings.HasPrefix(name, "_") {
|
|
|
|
|
name = "_" + name
|
|
|
|
|
}
|
|
|
|
|
pi := s.opts.PathParser.Parse(files.ComponentFolderLayouts, name)
|
|
|
|
|
ti, err := s.insertTemplate(pi, nil, false, s.treeMain)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ti != nil {
|
|
|
|
|
ti.Template = templ
|
|
|
|
|
ti.noBaseOf = true
|
|
|
|
|
ti.subCategory = SubCategoryInline
|
|
|
|
|
ti.D.IsPlainText = isText
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for templ := range s.allRawTemplates() {
|
|
|
|
|
if templ.Name() == "" || !isPartialName(templ.Name()) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
addIfNotSeen(false, p.templatesIn(p.parseHTML)...)
|
|
|
|
|
addIfNotSeen(true, p.templatesIn(p.parseText)...)
|
|
|
|
|
|
|
|
|
|
for _, t := range p.baseofHtmlClones {
|
|
|
|
|
if err := addIfNotSeen(false, p.templatesIn(t)...); err != nil {
|
|
|
|
|
if rebuild && s.templatesSnapshotSet.Contains(getParseTree(templ)) {
|
|
|
|
|
// This partial was not created during this build.
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
name := templ.Name()
|
|
|
|
|
if !paths.HasExt(name) {
|
|
|
|
|
// Assume HTML. This in line with how the lookup works.
|
|
|
|
|
name = name + s.htmlFormat.MediaType.FirstSuffix.FullSuffix
|
|
|
|
|
}
|
|
|
|
|
if !strings.HasPrefix(name, "_") {
|
|
|
|
|
name = "_" + name
|
|
|
|
|
}
|
|
|
|
|
pi := s.opts.PathParser.Parse(files.ComponentFolderLayouts, name)
|
|
|
|
|
ti, err := s.insertTemplate(pi, nil, SubCategoryInline, false, s.treeMain)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for _, t := range p.baseofTextClones {
|
|
|
|
|
if err := addIfNotSeen(true, p.templatesIn(t)...); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
|
|
if ti != nil {
|
|
|
|
|
ti.Template = templ
|
|
|
|
|
ti.noBaseOf = true
|
|
|
|
|
ti.subCategory = SubCategoryInline
|
|
|
|
|
ti.D.IsPlainText = isText(templ)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *TemplateStore) allRawTemplates() iter.Seq[tpl.Template] {
|
|
|
|
|
p := s.tns
|
|
|
|
|
return func(yield func(tpl.Template) bool) {
|
|
|
|
|
for t := range p.templatesIn(p.parseHTML) {
|
|
|
|
|
if !yield(t) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for t := range p.templatesIn(p.parseText) {
|
|
|
|
|
if !yield(t) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range p.baseofHtmlClones {
|
|
|
|
|
for t := range p.templatesIn(tt) {
|
|
|
|
|
if !yield(t) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for _, tt := range p.baseofTextClones {
|
|
|
|
|
for t := range p.templatesIn(tt) {
|
|
|
|
|
if !yield(t) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *TemplateStore) insertEmbedded() error {
|
|
|
|
|
return fs.WalkDir(embeddedTemplatesFs, ".", func(path string, d fs.DirEntry, err error) error {
|
|
|
|
|
if err != nil {
|
|
|
|
@@ -1024,7 +1048,7 @@ func (s *TemplateStore) insertEmbedded() error {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ti, err = s.insertTemplate(pi, nil, false, s.treeMain)
|
|
|
|
|
ti, err = s.insertTemplate(pi, nil, SubCategoryEmbedded, false, s.treeMain)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
@@ -1105,7 +1129,7 @@ func (s *TemplateStore) insertShortcode(pi *paths.Path, fi hugofs.FileMetaInfo,
|
|
|
|
|
return ti, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *TemplateStore) insertTemplate(pi *paths.Path, fi hugofs.FileMetaInfo, replace bool, tree doctree.Tree[map[nodeKey]*TemplInfo]) (*TemplInfo, error) {
|
|
|
|
|
func (s *TemplateStore) insertTemplate(pi *paths.Path, fi hugofs.FileMetaInfo, subCategory SubCategory, replace bool, tree doctree.Tree[map[nodeKey]*TemplInfo]) (*TemplInfo, error) {
|
|
|
|
|
key, _, category, d, err := s.toKeyCategoryAndDescriptor(pi)
|
|
|
|
|
// See #13577. Warn for now.
|
|
|
|
|
if err != nil {
|
|
|
|
@@ -1119,7 +1143,7 @@ func (s *TemplateStore) insertTemplate(pi *paths.Path, fi hugofs.FileMetaInfo, r
|
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return s.insertTemplate2(pi, fi, key, category, d, replace, false, tree)
|
|
|
|
|
return s.insertTemplate2(pi, fi, key, category, subCategory, d, replace, false, tree)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *TemplateStore) insertTemplate2(
|
|
|
|
@@ -1127,6 +1151,7 @@ func (s *TemplateStore) insertTemplate2(
|
|
|
|
|
fi hugofs.FileMetaInfo,
|
|
|
|
|
key string,
|
|
|
|
|
category Category,
|
|
|
|
|
subCategory SubCategory,
|
|
|
|
|
d TemplateDescriptor,
|
|
|
|
|
replace, isLegacyMapped bool,
|
|
|
|
|
tree doctree.Tree[map[nodeKey]*TemplInfo],
|
|
|
|
@@ -1160,6 +1185,11 @@ func (s *TemplateStore) insertTemplate2(
|
|
|
|
|
replace = fi.Meta().ModuleOrdinal < nkExisting.Fi.Meta().ModuleOrdinal
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !replace && existingFound {
|
|
|
|
|
// Always replace inline partials to allow for reloading.
|
|
|
|
|
replace = subCategory == SubCategoryInline && nkExisting.subCategory == SubCategoryInline
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !replace && existingFound {
|
|
|
|
|
if len(pi.Identifiers()) >= len(nkExisting.PathInfo.Identifiers()) {
|
|
|
|
|
// e.g. /pages/home.foo.html and /pages/home.html where foo may be a valid language name in another site.
|
|
|
|
@@ -1190,7 +1220,7 @@ func (s *TemplateStore) insertTemplate2(
|
|
|
|
|
return ti, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) bool, replace bool) error {
|
|
|
|
|
func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) bool, partialRebuild bool) error {
|
|
|
|
|
if include == nil {
|
|
|
|
|
include = func(fi hugofs.FileMetaInfo) bool {
|
|
|
|
|
return true
|
|
|
|
@@ -1372,7 +1402,7 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if replace && pi.NameNoIdentifier() == baseNameBaseof {
|
|
|
|
|
if partialRebuild && pi.NameNoIdentifier() == baseNameBaseof {
|
|
|
|
|
// A baseof file has changed.
|
|
|
|
|
resetBaseVariants = true
|
|
|
|
|
}
|
|
|
|
@@ -1380,12 +1410,12 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
|
|
|
|
|
var ti *TemplInfo
|
|
|
|
|
var err error
|
|
|
|
|
if pi.Type() == paths.TypeShortcode {
|
|
|
|
|
ti, err = s.insertShortcode(pi, fi, replace, s.treeShortcodes)
|
|
|
|
|
ti, err = s.insertShortcode(pi, fi, partialRebuild, s.treeShortcodes)
|
|
|
|
|
if err != nil || ti == nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ti, err = s.insertTemplate(pi, fi, replace, s.treeMain)
|
|
|
|
|
ti, err = s.insertTemplate(pi, fi, SubCategoryMain, partialRebuild, s.treeMain)
|
|
|
|
|
if err != nil || ti == nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
@@ -1419,7 +1449,7 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
|
|
|
|
|
desc.IsPlainText = outputFormat.IsPlainText
|
|
|
|
|
desc.MediaType = mediaType.Type
|
|
|
|
|
|
|
|
|
|
ti, err := s.insertTemplate2(pi, fi, targetPath, category, desc, true, true, s.treeMain)
|
|
|
|
|
ti, err := s.insertTemplate2(pi, fi, targetPath, category, SubCategoryMain, desc, true, true, s.treeMain)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
@@ -1430,6 +1460,7 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
|
|
|
|
|
if err := s.tns.readTemplateInto(ti); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if resetBaseVariants {
|
|
|
|
@@ -1456,7 +1487,15 @@ func (s *TemplateStore) key(dir string) string {
|
|
|
|
|
return paths.TrimTrailing(dir)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *TemplateStore) parseTemplates() error {
|
|
|
|
|
func (s *TemplateStore) createTemplatesSnapshot() error {
|
|
|
|
|
s.templatesSnapshotSet.Reset()
|
|
|
|
|
for t := range s.allRawTemplates() {
|
|
|
|
|
s.templatesSnapshotSet.Set(getParseTree(t), struct{}{})
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *TemplateStore) parseTemplates(replace bool) error {
|
|
|
|
|
if err := func() error {
|
|
|
|
|
// Read and parse all templates.
|
|
|
|
|
for _, v := range s.treeMain.All() {
|
|
|
|
@@ -1464,7 +1503,7 @@ func (s *TemplateStore) parseTemplates() error {
|
|
|
|
|
if vv.state == processingStateTransformed {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if err := s.parseTemplate(vv); err != nil {
|
|
|
|
|
if err := s.parseTemplate(vv, replace); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -1484,7 +1523,7 @@ func (s *TemplateStore) parseTemplates() error {
|
|
|
|
|
// The regular expression used to detect if a template needs a base template has some
|
|
|
|
|
// rare false positives. Assume we don't need one.
|
|
|
|
|
vv.noBaseOf = true
|
|
|
|
|
if err := s.parseTemplate(vv); err != nil {
|
|
|
|
|
if err := s.parseTemplate(vv, replace); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
@@ -1513,7 +1552,7 @@ func (s *TemplateStore) parseTemplates() error {
|
|
|
|
|
if vvv.state == processingStateTransformed {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if err := s.parseTemplate(vvv); err != nil {
|
|
|
|
|
if err := s.parseTemplate(vvv, replace); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|