Skip to content

Commit

Permalink
Fix shortcode detection in RenderString
Browse files Browse the repository at this point in the history
Fixes #10654
  • Loading branch information
bep committed Jan 26, 2023
1 parent 4ef9baf commit 1688583
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 2 deletions.
4 changes: 2 additions & 2 deletions hugolib/page__per_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,8 @@ func (p *pageContentOutput) RenderString(args ...any) (template.HTML, error) {

var rendered []byte

if strings.Contains(contentToRender, "{{") {
// Probably a shortcode.
if pageparser.HasShortcode(contentToRender) {
// String contains a shortcode.
parsed, err := pageparser.ParseMain(strings.NewReader(contentToRender), pageparser.Config{})
if err != nil {
return "", err
Expand Down
36 changes: 36 additions & 0 deletions hugolib/renderstring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,39 @@ Has other: false
`)

}

func TestRenderStringWithShortcodeIssue10654(t *testing.T) {
t.Parallel()

files := `
-- config.toml --
timeout = '300ms'
-- content/p1.md --
---
title: "P1"
---
{{< toc >}}
## Heading 1
{{< noop >}}
{{ not a shortcode
{{< /noop >}}
}
-- layouts/shortcodes/noop.html --
{{ .Inner | $.Page.RenderString }}
-- layouts/shortcodes/toc.html --
{{ .Page.TableOfContents }}
-- layouts/_default/single.html --
{{ .Content }}
`

b := NewIntegrationTestBuilder(
IntegrationTestConfig{
T: t,
TxtarString: files,
},
).Build()

b.AssertFileContent("public/p1/index.html", `TableOfContents`)
}
13 changes: 13 additions & 0 deletions parser/pageparser/pageparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"fmt"
"io"
"io/ioutil"
"regexp"
"strings"

"github.com/gohugoio/hugo/parser/metadecoders"
)
Expand Down Expand Up @@ -234,3 +236,14 @@ func IsProbablySourceOfItems(source []byte, items Items) bool {

return true
}

var hasShortcodeRe = regexp.MustCompile(`{{[%,<][^\/]`)

// HasShortcode returns true if the given string contains a shortcode.
func HasShortcode(s string) bool {
// Fast path for the common case.
if !strings.Contains(s, "{{") {
return false
}
return hasShortcodeRe.MatchString(s)
}
27 changes: 27 additions & 0 deletions parser/pageparser/pageparser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,30 @@ func TestIsProbablyItemsSource(t *testing.T) {
c.Assert(IsProbablySourceOfItems([]byte(`{{< foo >}} `), items), qt.IsFalse)
c.Assert(IsProbablySourceOfItems([]byte(``), items), qt.IsFalse)
}

func TestHasShortcode(t *testing.T) {
c := qt.New(t)

c.Assert(HasShortcode("{{< foo >}}"), qt.IsTrue)
c.Assert(HasShortcode("aSDasd SDasd aSD\n\nasdfadf{{% foo %}}\nasdf"), qt.IsTrue)
c.Assert(HasShortcode("{{</* foo */>}}"), qt.IsFalse)
c.Assert(HasShortcode("{{%/* foo */%}}"), qt.IsFalse)

}

func BenchmarkHasShortcode(b *testing.B) {
withShortcode := strings.Repeat("this is text", 30) + "{{< myshortcode >}}This is some inner content.{{< /myshortcode >}}" + strings.Repeat("this is text", 30)
withoutShortcode := strings.Repeat("this is text", 30) + "This is some inner content." + strings.Repeat("this is text", 30)
b.Run("Match", func(b *testing.B) {
for i := 0; i < b.N; i++ {
HasShortcode(withShortcode)
}
})

b.Run("NoMatch", func(b *testing.B) {
for i := 0; i < b.N; i++ {
HasShortcode(withoutShortcode)
}
})

}

0 comments on commit 1688583

Please sign in to comment.