markup/asciidocext: Improve Asciidoctor integration

Fixes an issue where improper attribute derivation from the page's
relative permalink caused failures with `outdir`, `imagesoutdir`, and
`imagesdir` when `markup.asciidocext.workingFolderCurrent` is enabled.
The updated logic now correctly handles:

- Multi-byte characters
- Multilingual multi-host sites
- Site builds from a subdirectory
- Pages using ugly URLs

Supports diagram caching as implemented in v3.1.0 of the asciidoctor-diagram
extension:

- Enables caching by default
- Sets default cache location to the compiled value of caches.misc.dir

Reduces duration of integration tests by:

- Generating GoAT diagrams instead of Ditaa diagrams
- Taking advantage of asciidoctor-diagram caching

Closes #9202
Closes #10183
Closes #10473
Closes #14160
This commit is contained in:
Joe Mooring
2025-10-24 12:11:54 -07:00
committed by Bjørn Erik Pedersen
parent 34b0c15a54
commit 3d21b0687b
17 changed files with 1949 additions and 673 deletions
+1 -8
View File
@@ -46,19 +46,12 @@ jobs:
uses: ruby/setup-ruby@8aeb6ff8030dd539317f8e1769a044873b56ea71 # v1.268.0 uses: ruby/setup-ruby@8aeb6ff8030dd539317f8e1769a044873b56ea71 # v1.268.0
with: with:
ruby-version: "3.4.5" ruby-version: "3.4.5"
- name: Install gems - name: Install Ruby gems
run: | run: |
gem install asciidoctor -v "2.0.26" gem install asciidoctor -v "2.0.26"
gem install asciidoctor-diagram -v "3.1.0" gem install asciidoctor-diagram -v "3.1.0"
gem install asciidoctor-diagram-ditaamini -v "1.0.3"
- name: Install GoAT - name: Install GoAT
run: go install github.com/blampe/goat/cmd/goat@177de93b192b8ffae608e5d9ec421cc99bf68402 run: go install github.com/blampe/goat/cmd/goat@177de93b192b8ffae608e5d9ec421cc99bf68402
- name: Install Java # required by asciidoctor-diagram-ditaamini
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
distribution: temurin
java-version: "25"
java-package: jre
- name: Install Python - name: Install Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with: with:
+7
View File
@@ -51,11 +51,18 @@ const (
type Configs map[string]FileCacheConfig type Configs map[string]FileCacheConfig
// CacheDirModules returns the compiled path to the modules cache.
// For internal use. // For internal use.
func (c Configs) CacheDirModules() string { func (c Configs) CacheDirModules() string {
return c[CacheKeyModules].DirCompiled return c[CacheKeyModules].DirCompiled
} }
// CacheDirMisc returns the compiled path to the misc cache.
// For internal use.
func (c Configs) CacheDirMisc() string {
return c[CacheKeyMisc].DirCompiled
}
var defaultCacheConfigs = Configs{ var defaultCacheConfigs = Configs{
CacheKeyModules: { CacheKeyModules: {
MaxAge: -1, MaxAge: -1,
+4
View File
@@ -135,6 +135,10 @@ func (c ConfigLanguage) WorkingDir() string {
return c.m.Base.WorkingDir return c.m.Base.WorkingDir
} }
func (c ConfigLanguage) CacheDirMisc() string {
return c.config.Caches.CacheDirMisc()
}
func (c ConfigLanguage) Quiet() bool { func (c ConfigLanguage) Quiet() bool {
return c.m.Base.Internal.Quiet return c.m.Base.Internal.Quiet
} }
+1
View File
@@ -79,6 +79,7 @@ type AllProvider interface {
WorkingDir() string WorkingDir() string
EnableEmoji() bool EnableEmoji() bool
ConfiguredDimensions() *sitesmatrix.ConfiguredDimensions ConfiguredDimensions() *sitesmatrix.ConfiguredDimensions
CacheDirMisc() string
} }
// We cannot import the media package as that would create a circular dependency. // We cannot import the media package as that would create a circular dependency.
+471 -469
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -121,7 +121,7 @@ func IsGitHubAction() bool {
} }
// SupportsAll reports whether the running system supports all Hugo features, // SupportsAll reports whether the running system supports all Hugo features,
// e.g. Asciidoc, Pandoc etc. // e.g. AsciiDoc, Pandoc etc.
func SupportsAll() bool { func SupportsAll() bool {
return IsGitHubAction() || os.Getenv("CI_LOCAL") != "" return IsGitHubAction() || os.Getenv("CI_LOCAL") != ""
} }
+3 -3
View File
@@ -345,7 +345,7 @@ func testAllMarkdownEnginesForPages(t *testing.T,
shouldExecute func() bool shouldExecute func() bool
}{ }{
{"md", func() bool { return true }}, {"md", func() bool { return true }},
{"ad", func() bool { return asciidocext.Supports() }}, {"ad", func() bool { ok, _ := asciidocext.Supports(); return ok }},
{"rst", func() bool { return !htesting.IsRealCI() && rst.Supports() }}, {"rst", func() bool { return !htesting.IsRealCI() && rst.Supports() }},
} }
@@ -574,7 +574,7 @@ func TestPageSummary(t *testing.T) {
assertFunc := func(t *testing.T, ext string, pages page.Pages) { assertFunc := func(t *testing.T, ext string, pages page.Pages) {
p := pages[0] p := pages[0]
checkPageTitle(t, p, "SimpleWithoutSummaryDelimiter") checkPageTitle(t, p, "SimpleWithoutSummaryDelimiter")
// Source is not Asciidoctor- or RST-compatible so don't test them // Source is not AsciiDoc- or RST-compatible so don't test them
if ext != "ad" && ext != "rst" { if ext != "ad" && ext != "rst" {
checkPageContent(t, p, normalizeExpected(ext, "<p><a href=\"https://lipsum.com/\">Lorem ipsum</a> dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\n\n<p>Additional text.</p>\n\n<p>Further text.</p>\n"), ext) checkPageContent(t, p, normalizeExpected(ext, "<p><a href=\"https://lipsum.com/\">Lorem ipsum</a> dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\n\n<p>Additional text.</p>\n\n<p>Further text.</p>\n"), ext)
checkPageSummary(t, p, normalizeExpected(ext, "<p><a href=\"https://lipsum.com/\">Lorem ipsum</a> dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p><p>Additional text.</p>"), ext) checkPageSummary(t, p, normalizeExpected(ext, "<p><a href=\"https://lipsum.com/\">Lorem ipsum</a> dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p><p>Additional text.</p>"), ext)
@@ -604,7 +604,7 @@ func TestPageWithSummaryParameter(t *testing.T) {
p := pages[0] p := pages[0]
checkPageTitle(t, p, "SimpleWithSummaryParameter") checkPageTitle(t, p, "SimpleWithSummaryParameter")
checkPageContent(t, p, normalizeExpected(ext, "<p>Some text.</p>\n\n<p>Some more text.</p>\n"), ext) checkPageContent(t, p, normalizeExpected(ext, "<p>Some text.</p>\n\n<p>Some more text.</p>\n"), ext)
// Summary is not Asciidoctor- or RST-compatible so don't test them // Summary is not AsciiDoc- or RST-compatible so don't test them
if ext != "ad" && ext != "rst" { if ext != "ad" && ext != "rst" {
checkPageSummary(t, p, normalizeExpected(ext, "Page with summary parameter and <a href=\"http://www.example.com/\">a link</a>"), ext) checkPageSummary(t, p, normalizeExpected(ext, "Page with summary parameter and <a href=\"http://www.example.com/\">a link</a>"), ext)
} }
@@ -132,7 +132,7 @@ docs/p1/sub/mymixcasetext2.txt
b.AssertFileContent("public/docs/p3/index.html", "<strong>Hello World Default</strong>") b.AssertFileContent("public/docs/p3/index.html", "<strong>Hello World Default</strong>")
} }
func TestPagesFromGoTmplAsciidocAndSimilar(t *testing.T) { func TestPagesFromGoTmplAsciiDocAndSimilar(t *testing.T) {
files := ` files := `
-- hugo.toml -- -- hugo.toml --
disableKinds = ["taxonomy", "term", "rss", "sitemap"] disableKinds = ["taxonomy", "term", "rss", "sitemap"]
@@ -153,7 +153,7 @@ allow = ['asciidoctor', 'pandoc','rst2html', 'python']
b := hugolib.Test(t, files) b := hugolib.Test(t, files)
if asciidocext.Supports() { if ok, _ := asciidocext.Supports(); ok {
b.AssertFileContent("public/docs/asciidoc/index.html", b.AssertFileContent("public/docs/asciidoc/index.html",
"Mark my words, <mark>automation is essential</mark>", "Mark my words, <mark>automation is essential</mark>",
"Path: /docs/asciidoc|", "Path: /docs/asciidoc|",
@@ -503,7 +503,7 @@ baseURL = "https://example.com"
func TestPagesFromGoTmplCascade(t *testing.T) { func TestPagesFromGoTmplCascade(t *testing.T) {
t.Parallel() t.Parallel()
files := ` files := `
-- hugo.toml -- -- hugo.toml --
disableKinds = ["taxonomy", "term", "rss", "sitemap"] disableKinds = ["taxonomy", "term", "rss", "sitemap"]
baseURL = "https://example.com" baseURL = "https://example.com"
@@ -523,7 +523,7 @@ baseURL = "https://example.com"
func TestPagesFromGoBuildOptions(t *testing.T) { func TestPagesFromGoBuildOptions(t *testing.T) {
t.Parallel() t.Parallel()
files := ` files := `
-- hugo.toml -- -- hugo.toml --
disableKinds = ["taxonomy", "term", "rss", "sitemap"] disableKinds = ["taxonomy", "term", "rss", "sitemap"]
baseURL = "https://example.com" baseURL = "https://example.com"
@@ -644,11 +644,11 @@ func TestPagesFromGoTmplMenusMap(t *testing.T) {
-- hugo.toml -- -- hugo.toml --
disableKinds = ['rss','section','sitemap','taxonomy','term'] disableKinds = ['rss','section','sitemap','taxonomy','term']
-- content/_content.gotmpl -- -- content/_content.gotmpl --
{{ $menu1 := dict {{ $menu1 := dict
"parent" "main-page" "parent" "main-page"
"identifier" "id1" "identifier" "id1"
}} }}
{{ $menu2 := dict {{ $menu2 := dict
"parent" "main-page" "parent" "main-page"
"identifier" "id2" "identifier" "id2"
}} }}
@@ -859,7 +859,7 @@ Title: {{ .Title }}|Content: {{ .Content }}|
func TestPagesFromGoTmplHome(t *testing.T) { func TestPagesFromGoTmplHome(t *testing.T) {
t.Parallel() t.Parallel()
files := ` files := `
-- hugo.toml -- -- hugo.toml --
disableKinds = ["taxonomy", "term", "rss", "sitemap"] disableKinds = ["taxonomy", "term", "rss", "sitemap"]
baseURL = "https://example.com" baseURL = "https://example.com"
+3 -3
View File
@@ -1927,9 +1927,9 @@ Myotherpartial Inline.|{{ .Title }}|
b.AssertFileContent("public/index.html", "My inline partial in all Edited.") b.AssertFileContent("public/index.html", "My inline partial in all Edited.")
} }
func TestRebuildEditAsciidocContentFile(t *testing.T) { func TestRebuildEditAsciiDocContentFile(t *testing.T) {
if !asciidocext.Supports() { if ok, err := asciidocext.Supports(); !ok {
t.Skip("skip asciidoc") t.Skip(err)
} }
files := ` files := `
-- hugo.toml -- -- hugo.toml --
+3 -3
View File
@@ -54,10 +54,10 @@ baseURL = "https://example.org"
Test(c, files) Test(c, files)
}) })
c.Run("Asciidoc, denied", func(c *qt.C) { c.Run("AsciiDoc, denied", func(c *qt.C) {
c.Parallel() c.Parallel()
if !asciidocext.Supports() { if ok, err := asciidocext.Supports(); !ok {
c.Skip() c.Skip(err)
} }
files := ` files := `
File diff suppressed because it is too large Load Diff
+25 -8
View File
@@ -29,21 +29,38 @@ type provider struct{}
func (p provider) New(cfg converter.ProviderConfig) (converter.Provider, error) { func (p provider) New(cfg converter.ProviderConfig) (converter.Provider, error) {
return converter.NewProvider("asciidocext", func(ctx converter.DocumentContext) (converter.Converter, error) { return converter.NewProvider("asciidocext", func(ctx converter.DocumentContext) (converter.Converter, error) {
return &internal.AsciidocConverter{ return &internal.AsciiDocConverter{
Ctx: ctx, Ctx: ctx,
Cfg: cfg, Cfg: cfg,
}, nil }, nil
}), nil }), nil
} }
// Supports returns whether Asciidoctor is installed on this computer. // Supports reports whether the AsciiDoc converter is installed. Only used in
func Supports() bool { // tests.
hasBin := internal.HasAsciiDoc() func Supports() (bool, error) {
hasAsciiDoc, err := internal.HasAsciiDoc()
if htesting.SupportsAll() { if htesting.SupportsAll() {
if !hasBin { if !hasAsciiDoc {
panic("asciidoctor not installed") panic(err)
} }
return true return true, nil
} }
return hasBin
return hasAsciiDoc, err
}
// SupportsGoATDiagrams reports whether the AsciiDoc converter can render GoAT
// diagrams. Only used in tests.
func SupportsGoATDiagrams() (bool, error) {
supportsGoATDiagrams, err := internal.CanRenderGoATDiagrams()
if htesting.SupportsAll() {
if !supportsGoATDiagrams {
panic(err)
}
return true, nil
}
return supportsGoATDiagrams, err
} }
+85 -113
View File
@@ -11,14 +11,14 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// Package asciidocext converts AsciiDoc to HTML using Asciidoctor // Package asciidocext converts AsciiDoc to HTML using the Asciidoctor
// external binary. The `asciidoc` module is reserved for a future golang // external binary. The `asciidoc` module is reserved for a future golang
// implementation. // implementation.
package asciidocext_test package asciidocext_test
import ( import (
"path/filepath" "encoding/json"
"testing" "testing"
"github.com/gohugoio/hugo/common/collections" "github.com/gohugoio/hugo/common/collections"
@@ -28,6 +28,7 @@ import (
"github.com/gohugoio/hugo/config/security" "github.com/gohugoio/hugo/config/security"
"github.com/gohugoio/hugo/config/testconfig" "github.com/gohugoio/hugo/config/testconfig"
"github.com/gohugoio/hugo/markup/asciidocext" "github.com/gohugoio/hugo/markup/asciidocext"
"github.com/gohugoio/hugo/markup/asciidocext/asciidocext_config"
"github.com/gohugoio/hugo/markup/asciidocext/internal" "github.com/gohugoio/hugo/markup/asciidocext/internal"
"github.com/gohugoio/hugo/markup/converter" "github.com/gohugoio/hugo/markup/converter"
"github.com/gohugoio/hugo/markup/markup_config" "github.com/gohugoio/hugo/markup/markup_config"
@@ -36,6 +37,24 @@ import (
qt "github.com/frankban/quicktest" qt "github.com/frankban/quicktest"
) )
var defaultAsciiDocExtConfigAsJSON []byte
func init() {
var err error
defaultAsciiDocExtConfigAsJSON, err = json.Marshal(markup_config.Default.AsciiDocExt)
if err != nil {
panic(err)
}
}
func resetDefaultAsciiDocExtConfig() {
markup_config.Default.AsciiDocExt = asciidocext_config.Config{}
err := json.Unmarshal(defaultAsciiDocExtConfigAsJSON, &markup_config.Default.AsciiDocExt)
if err != nil {
panic(err)
}
}
func TestAsciidoctorDefaultArgs(t *testing.T) { func TestAsciidoctorDefaultArgs(t *testing.T) {
c := qt.New(t) c := qt.New(t)
cfg := config.New() cfg := config.New()
@@ -52,24 +71,30 @@ func TestAsciidoctorDefaultArgs(t *testing.T) {
conv, err := p.New(converter.DocumentContext{}) conv, err := p.New(converter.DocumentContext{})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
ac := conv.(*internal.AsciidocConverter) ac := conv.(*internal.AsciiDocConverter)
c.Assert(ac, qt.Not(qt.IsNil)) c.Assert(ac, qt.Not(qt.IsNil))
args := ac.ParseArgs(converter.DocumentContext{}) args, err := ac.ParseArgs(converter.DocumentContext{})
c.Assert(err, qt.IsNil)
expected := []string{"--no-header-footer"} expected := []string{"--no-header-footer"}
c.Assert(args, qt.DeepEquals, expected) c.Assert(args, qt.DeepEquals, expected)
} }
func TestAsciidoctorNonDefaultArgs(t *testing.T) { func TestAsciidoctorNonDefaultArgs(t *testing.T) {
c := qt.New(t) c := qt.New(t)
t.Cleanup(func() {
resetDefaultAsciiDocExtConfig()
})
mconf := markup_config.Default mconf := markup_config.Default
mconf.AsciidocExt.Backend = "manpage" mconf.AsciiDocExt.Backend = "manpage"
mconf.AsciidocExt.NoHeaderOrFooter = false mconf.AsciiDocExt.NoHeaderOrFooter = false
mconf.AsciidocExt.SafeMode = "safe" mconf.AsciiDocExt.SafeMode = "safe"
mconf.AsciidocExt.SectionNumbers = true mconf.AsciiDocExt.SectionNumbers = true
mconf.AsciidocExt.Verbose = true mconf.AsciiDocExt.Verbose = true
mconf.AsciidocExt.Trace = false mconf.AsciiDocExt.Trace = false
mconf.AsciidocExt.FailureLevel = "warn" mconf.AsciiDocExt.FailureLevel = "warn"
conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf) conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf)
@@ -84,22 +109,28 @@ func TestAsciidoctorNonDefaultArgs(t *testing.T) {
conv, err := p.New(converter.DocumentContext{}) conv, err := p.New(converter.DocumentContext{})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
ac := conv.(*internal.AsciidocConverter) ac := conv.(*internal.AsciiDocConverter)
c.Assert(ac, qt.Not(qt.IsNil)) c.Assert(ac, qt.Not(qt.IsNil))
args := ac.ParseArgs(converter.DocumentContext{}) args, err := ac.ParseArgs(converter.DocumentContext{})
c.Assert(err, qt.IsNil)
expected := []string{"-b", "manpage", "--section-numbers", "--verbose", "--failure-level", "warn", "--safe-mode", "safe"} expected := []string{"-b", "manpage", "--section-numbers", "--verbose", "--failure-level", "warn", "--safe-mode", "safe"}
c.Assert(args, qt.DeepEquals, expected) c.Assert(args, qt.DeepEquals, expected)
} }
func TestAsciidoctorDisallowedArgs(t *testing.T) { func TestAsciidoctorDisallowedArgs(t *testing.T) {
c := qt.New(t) c := qt.New(t)
t.Cleanup(func() {
resetDefaultAsciiDocExtConfig()
})
mconf := markup_config.Default mconf := markup_config.Default
mconf.AsciidocExt.Backend = "disallowed-backend" mconf.AsciiDocExt.Backend = "disallowed-backend"
mconf.AsciidocExt.Extensions = []string{"./disallowed-extension"} mconf.AsciiDocExt.Extensions = []string{"./disallowed-extension"}
mconf.AsciidocExt.Attributes = map[string]any{"outdir": "disallowed-attribute"} mconf.AsciiDocExt.Attributes = map[string]any{"outdir": "disallowed-attribute"}
mconf.AsciidocExt.SafeMode = "disallowed-safemode" mconf.AsciiDocExt.SafeMode = "disallowed-safemode"
mconf.AsciidocExt.FailureLevel = "disallowed-failurelevel" mconf.AsciiDocExt.FailureLevel = "disallowed-failurelevel"
conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf) conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf)
@@ -114,18 +145,24 @@ func TestAsciidoctorDisallowedArgs(t *testing.T) {
conv, err := p.New(converter.DocumentContext{}) conv, err := p.New(converter.DocumentContext{})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
ac := conv.(*internal.AsciidocConverter) ac := conv.(*internal.AsciiDocConverter)
c.Assert(ac, qt.Not(qt.IsNil)) c.Assert(ac, qt.Not(qt.IsNil))
args := ac.ParseArgs(converter.DocumentContext{}) args, err := ac.ParseArgs(converter.DocumentContext{})
c.Assert(err, qt.IsNil)
expected := []string{"--no-header-footer"} expected := []string{"--no-header-footer"}
c.Assert(args, qt.DeepEquals, expected) c.Assert(args, qt.DeepEquals, expected)
} }
func TestAsciidoctorArbitraryExtension(t *testing.T) { func TestAsciidoctorArbitraryExtension(t *testing.T) {
c := qt.New(t) c := qt.New(t)
t.Cleanup(func() {
resetDefaultAsciiDocExtConfig()
})
mconf := markup_config.Default mconf := markup_config.Default
mconf.AsciidocExt.Extensions = []string{"arbitrary-extension"} mconf.AsciiDocExt.Extensions = []string{"arbitrary-extension"}
conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf) conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf)
p, err := asciidocext.Provider.New( p, err := asciidocext.Provider.New(
converter.ProviderConfig{ converter.ProviderConfig{
@@ -138,10 +175,11 @@ func TestAsciidoctorArbitraryExtension(t *testing.T) {
conv, err := p.New(converter.DocumentContext{}) conv, err := p.New(converter.DocumentContext{})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
ac := conv.(*internal.AsciidocConverter) ac := conv.(*internal.AsciiDocConverter)
c.Assert(ac, qt.Not(qt.IsNil)) c.Assert(ac, qt.Not(qt.IsNil))
args := ac.ParseArgs(converter.DocumentContext{}) args, err := ac.ParseArgs(converter.DocumentContext{})
c.Assert(err, qt.IsNil)
expected := []string{"-r", "arbitrary-extension", "--no-header-footer"} expected := []string{"-r", "arbitrary-extension", "--no-header-footer"}
c.Assert(args, qt.DeepEquals, expected) c.Assert(args, qt.DeepEquals, expected)
} }
@@ -149,6 +187,10 @@ func TestAsciidoctorArbitraryExtension(t *testing.T) {
func TestAsciidoctorDisallowedExtension(t *testing.T) { func TestAsciidoctorDisallowedExtension(t *testing.T) {
c := qt.New(t) c := qt.New(t)
t.Cleanup(func() {
resetDefaultAsciiDocExtConfig()
})
for _, disallowedExtension := range []string{ for _, disallowedExtension := range []string{
`foo-bar//`, `foo-bar//`,
`foo-bar\\ `, `foo-bar\\ `,
@@ -159,7 +201,7 @@ func TestAsciidoctorDisallowedExtension(t *testing.T) {
`foo.bar`, `foo.bar`,
} { } {
mconf := markup_config.Default mconf := markup_config.Default
mconf.AsciidocExt.Extensions = []string{disallowedExtension} mconf.AsciiDocExt.Extensions = []string{disallowedExtension}
conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf) conf := testconfig.GetTestConfigSectionFromStruct("markup", mconf)
p, err := asciidocext.Provider.New( p, err := asciidocext.Provider.New(
converter.ProviderConfig{ converter.ProviderConfig{
@@ -172,94 +214,23 @@ func TestAsciidoctorDisallowedExtension(t *testing.T) {
conv, err := p.New(converter.DocumentContext{}) conv, err := p.New(converter.DocumentContext{})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
ac := conv.(*internal.AsciidocConverter) ac := conv.(*internal.AsciiDocConverter)
c.Assert(ac, qt.Not(qt.IsNil)) c.Assert(ac, qt.Not(qt.IsNil))
args := ac.ParseArgs(converter.DocumentContext{}) args, err := ac.ParseArgs(converter.DocumentContext{})
c.Assert(err, qt.IsNil)
expected := []string{"--no-header-footer"} expected := []string{"--no-header-footer"}
c.Assert(args, qt.DeepEquals, expected) c.Assert(args, qt.DeepEquals, expected)
} }
} }
func TestAsciidoctorWorkingFolderCurrent(t *testing.T) {
c := qt.New(t)
cfg := config.FromTOMLConfigString(`
[markup]
[markup.asciidocext]
workingFolderCurrent = true
trace = false
`)
conf := testconfig.GetTestConfig(afero.NewMemMapFs(), cfg)
p, err := asciidocext.Provider.New(
converter.ProviderConfig{
Conf: conf,
Logger: loggers.NewDefault(),
},
)
c.Assert(err, qt.IsNil)
ctx := converter.DocumentContext{Filename: "/tmp/hugo_asciidoc_ddd/docs/chapter2/index.adoc", DocumentName: "chapter2/index.adoc"}
conv, err := p.New(ctx)
c.Assert(err, qt.IsNil)
ac := conv.(*internal.AsciidocConverter)
c.Assert(ac, qt.Not(qt.IsNil))
args := ac.ParseArgs(ctx)
c.Assert(len(args), qt.Equals, 5)
c.Assert(args[0], qt.Equals, "--base-dir")
c.Assert(filepath.ToSlash(args[1]), qt.Matches, "/tmp/hugo_asciidoc_ddd/docs/chapter2")
c.Assert(args[2], qt.Equals, "-a")
c.Assert(args[3], qt.Matches, `outdir=.*chapter2`)
c.Assert(args[4], qt.Equals, "--no-header-footer")
}
func TestAsciidoctorWorkingFolderCurrentAndExtensions(t *testing.T) {
c := qt.New(t)
cfg := config.FromTOMLConfigString(`
[markup]
[markup.asciidocext]
backend = "html5s"
workingFolderCurrent = true
trace = false
noHeaderOrFooter = true
extensions = ["asciidoctor-html5s", "asciidoctor-diagram"]
`)
conf := testconfig.GetTestConfig(afero.NewMemMapFs(), cfg)
p, err := asciidocext.Provider.New(
converter.ProviderConfig{
Conf: conf,
Logger: loggers.NewDefault(),
},
)
c.Assert(err, qt.IsNil)
conv, err := p.New(converter.DocumentContext{})
c.Assert(err, qt.IsNil)
ac := conv.(*internal.AsciidocConverter)
c.Assert(ac, qt.Not(qt.IsNil))
args := ac.ParseArgs(converter.DocumentContext{})
c.Assert(len(args), qt.Equals, 11)
c.Assert(args[0], qt.Equals, "-b")
c.Assert(args[1], qt.Equals, "html5s")
c.Assert(args[2], qt.Equals, "-r")
c.Assert(args[3], qt.Equals, "asciidoctor-html5s")
c.Assert(args[4], qt.Equals, "-r")
c.Assert(args[5], qt.Equals, "asciidoctor-diagram")
c.Assert(args[6], qt.Equals, "--base-dir")
c.Assert(args[7], qt.Equals, ".")
c.Assert(args[8], qt.Equals, "-a")
c.Assert(args[9], qt.Contains, "outdir=")
c.Assert(args[10], qt.Equals, "--no-header-footer")
}
func TestAsciidoctorAttributes(t *testing.T) { func TestAsciidoctorAttributes(t *testing.T) {
c := qt.New(t) c := qt.New(t)
t.Cleanup(func() {
resetDefaultAsciiDocExtConfig()
})
cfg := config.FromTOMLConfigString(` cfg := config.FromTOMLConfigString(`
[markup] [markup]
[markup.asciidocext] [markup.asciidocext]
@@ -282,7 +253,7 @@ my-attribute-false = false
conv, err := p.New(converter.DocumentContext{}) conv, err := p.New(converter.DocumentContext{})
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
ac := conv.(*internal.AsciidocConverter) ac := conv.(*internal.AsciiDocConverter)
c.Assert(ac, qt.Not(qt.IsNil)) c.Assert(ac, qt.Not(qt.IsNil))
expectedValues := map[string]bool{ expectedValues := map[string]bool{
@@ -292,7 +263,8 @@ my-attribute-false = false
"'!my-attribute-false'": true, "'!my-attribute-false'": true,
} }
args := ac.ParseArgs(converter.DocumentContext{}) args, err := ac.ParseArgs(converter.DocumentContext{})
c.Assert(err, qt.IsNil)
c.Assert(len(args), qt.Equals, 9) c.Assert(len(args), qt.Equals, 9)
c.Assert(args[0], qt.Equals, "-a") c.Assert(args[0], qt.Equals, "-a")
c.Assert(expectedValues[args[1]], qt.Equals, true) c.Assert(expectedValues[args[1]], qt.Equals, true)
@@ -329,8 +301,8 @@ allow = ['asciidoctor']
} }
func TestConvert(t *testing.T) { func TestConvert(t *testing.T) {
if !asciidocext.Supports() { if ok, err := asciidocext.Supports(); !ok {
t.Skip("asciidoctor not installed") t.Skip(err)
} }
c := qt.New(t) c := qt.New(t)
@@ -345,8 +317,8 @@ func TestConvert(t *testing.T) {
} }
func TestTableOfContents(t *testing.T) { func TestTableOfContents(t *testing.T) {
if !asciidocext.Supports() { if ok, err := asciidocext.Supports(); !ok {
t.Skip("asciidoctor not installed") t.Skip(err)
} }
c := qt.New(t) c := qt.New(t)
p := getProvider(c, "") p := getProvider(c, "")
@@ -387,8 +359,8 @@ testContent
} }
func TestTableOfContentsWithCode(t *testing.T) { func TestTableOfContentsWithCode(t *testing.T) {
if !asciidocext.Supports() { if ok, err := asciidocext.Supports(); !ok {
t.Skip("asciidoctor not installed") t.Skip(err)
} }
c := qt.New(t) c := qt.New(t)
p := getProvider(c, "") p := getProvider(c, "")
@@ -406,8 +378,8 @@ func TestTableOfContentsWithCode(t *testing.T) {
} }
func TestTableOfContentsPreserveTOC(t *testing.T) { func TestTableOfContentsPreserveTOC(t *testing.T) {
if !asciidocext.Supports() { if ok, err := asciidocext.Supports(); !ok {
t.Skip("asciidoctor not installed") t.Skip(err)
} }
c := qt.New(t) c := qt.New(t)
confStr := ` confStr := `
+175 -50
View File
@@ -2,11 +2,17 @@ package internal
import ( import (
"bytes" "bytes"
"fmt"
"net/url"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/gohugoio/hugo/common/hexec" "github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/config/security"
"github.com/gohugoio/hugo/identity" "github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/markup/asciidocext/asciidocext_config" "github.com/gohugoio/hugo/markup/asciidocext/asciidocext_config"
"github.com/gohugoio/hugo/markup/converter" "github.com/gohugoio/hugo/markup/converter"
"github.com/gohugoio/hugo/markup/internal" "github.com/gohugoio/hugo/markup/internal"
@@ -15,27 +21,52 @@ import (
"golang.org/x/net/html" "golang.org/x/net/html"
) )
type AsciidocConverter struct { type AsciiDocConverter struct {
Ctx converter.DocumentContext Ctx converter.DocumentContext
Cfg converter.ProviderConfig Cfg converter.ProviderConfig
} }
type AsciidocResult struct { type asciiDocResult struct {
converter.ResultRender converter.ResultRender
toc *tableofcontents.Fragments toc *tableofcontents.Fragments
} }
/* ToDo: RelPermalink patch for svg posts not working*/
type pageSubset interface { type pageSubset interface {
IsPage() bool
RelPermalink() string RelPermalink() string
Section() string
} }
func (r AsciidocResult) TableOfContents() *tableofcontents.Fragments { const (
// asciiDocBinaryName is name of the AsciiDoc converter CLI.
asciiDocBinaryName = "asciidoctor"
// asciiDocDiagramExtension is the name of the AsciiDoc converter diagram
// extension.
asciiDocDiagramExtension = "asciidoctor-diagram"
// asciiDocDiagramCacheDirKey is the AsciiDoc converter attribute key for
// setting the path to the diagram cache directory.
asciiDocDiagramCacheDirKey = "diagram-cachedir"
// asciiDocDiagramCacheImagesOptionKey is the AsciiDoc converter attribute
// key for determining whether to cache image files in addition to
// metadata files.
asciiDocDiagramCacheImagesOptionKey = "diagram-cache-images-option"
// gemBinaryName is the name of the RubyGems CLI.
gemBinaryName = "gem"
// goatBinaryName is the name of the GoAT CLI.
goatBinaryName = "goat"
)
func (r asciiDocResult) TableOfContents() *tableofcontents.Fragments {
return r.toc return r.toc
} }
func (a *AsciidocConverter) Convert(ctx converter.RenderContext) (converter.ResultRender, error) { func (a *AsciiDocConverter) Convert(ctx converter.RenderContext) (converter.ResultRender, error) {
b, err := a.GetAsciidocContent(ctx.Src, a.Ctx) b, err := a.GetAsciiDocContent(ctx.Src, a.Ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -43,50 +74,81 @@ func (a *AsciidocConverter) Convert(ctx converter.RenderContext) (converter.Resu
if err != nil { if err != nil {
return nil, err return nil, err
} }
return AsciidocResult{ return asciiDocResult{
ResultRender: converter.Bytes(content), ResultRender: converter.Bytes(content),
toc: toc, toc: toc,
}, nil }, nil
} }
func (a *AsciidocConverter) Supports(_ identity.Identity) bool { func (a *AsciiDocConverter) Supports(_ identity.Identity) bool {
return false return false
} }
// GetAsciidocContent calls asciidoctor as an external helper // GetAsciiDocContent calls asciidoctor as an external helper to convert
// to convert AsciiDoc content to HTML. // AsciiDoc content to HTML.
func (a *AsciidocConverter) GetAsciidocContent(src []byte, ctx converter.DocumentContext) ([]byte, error) { func (a *AsciiDocConverter) GetAsciiDocContent(src []byte, ctx converter.DocumentContext) ([]byte, error) {
if !HasAsciiDoc() { if ok, err := HasAsciiDoc(); !ok {
a.Cfg.Logger.Errorln("asciidoctor not found in $PATH: Please install.\n", a.Cfg.Logger.Errorf("leaving AsciiDoc content unrendered: %s", err.Error())
" Leaving AsciiDoc content unrendered.")
return src, nil return src, nil
} }
args := a.ParseArgs(ctx) args, err := a.ParseArgs(ctx)
args = append(args, "-") if err != nil {
return nil, err
}
args = append(args, "-") // read from stdin
a.Cfg.Logger.Infoln("Rendering", ctx.DocumentName, " using asciidoctor args", args, "...") a.Cfg.Logger.Infof("Rendering %s using Asciidoctor args %s ...", ctx.DocumentName, args)
return internal.ExternallyRenderContent(a.Cfg, ctx, src, asciiDocBinaryName, args) return internal.ExternallyRenderContent(a.Cfg, ctx, src, asciiDocBinaryName, args)
} }
func (a *AsciidocConverter) ParseArgs(ctx converter.DocumentContext) []string { func (a *AsciiDocConverter) ParseArgs(ctx converter.DocumentContext) ([]string, error) {
cfg := a.Cfg.MarkupConfig().AsciidocExt cfg := a.Cfg.MarkupConfig().AsciiDocExt
args := []string{} args := []string{}
args = a.AppendArg(args, "-b", cfg.Backend, asciidocext_config.CliDefault.Backend, asciidocext_config.AllowedBackend) args = a.AppendArg(args, "-b", cfg.Backend, asciidocext_config.CliDefault.Backend, asciidocext_config.AllowedBackend)
for _, extension := range cfg.Extensions { for _, extension := range cfg.Extensions {
if strings.LastIndexAny(extension, `\/.`) > -1 { if strings.LastIndexAny(extension, `\/.`) > -1 {
a.Cfg.Logger.Errorln("Unsupported asciidoctor extension was passed in. Extension `" + extension + "` ignored. Only installed asciidoctor extensions are allowed.") a.Cfg.Logger.Errorf(
"The %q Asciidoctor extension is unsupported and ignored. Only installed Asciidoctor extensions are allowed.",
extension,
)
continue continue
} }
args = append(args, "-r", extension) args = append(args, "-r", extension)
if extension == asciiDocDiagramExtension {
cacheDir := filepath.Clean(filepath.Join(a.Cfg.Conf.CacheDirMisc(), asciiDocDiagramExtension))
args = append(args, "-a", asciiDocDiagramCacheDirKey+"="+cacheDir)
args = append(args, "-a", asciiDocDiagramCacheImagesOptionKey)
}
} }
for attributeKey, attributeValue := range cfg.Attributes { for attributeKey, attributeValue := range cfg.Attributes {
if asciidocext_config.DisallowedAttributes[attributeKey] { if asciidocext_config.DisallowedAttributes[attributeKey] {
a.Cfg.Logger.Errorln("Unsupported asciidoctor attribute was passed in. Attribute `" + attributeKey + "` ignored.") a.Cfg.Logger.Errorf(
"The %q Asciidoctor attribute is unsupported and ignored.",
attributeKey,
)
continue
}
if attributeKey == asciiDocDiagramCacheImagesOptionKey {
a.Cfg.Logger.Warnf(
"The %q Asciidoctor attribute is fixed and cannot be modified. To disable caching of both image and metadata files, set markup.asciidocext.attributes.diagram-nocache-option to true in your site configuration.",
attributeKey,
)
continue
}
if attributeKey == asciiDocDiagramCacheDirKey {
a.Cfg.Logger.Warnf(
"The %q Asciidoctor attribute is fixed and cannot be modified. To change the cache location, modify caches.misc.dir in your site configuration.",
attributeKey,
)
continue continue
} }
@@ -105,42 +167,63 @@ func (a *AsciidocConverter) ParseArgs(ctx converter.DocumentContext) []string {
} }
if cfg.WorkingFolderCurrent { if cfg.WorkingFolderCurrent {
contentDir := filepath.Dir(ctx.Filename) page, ok := ctx.Document.(pageSubset)
destinationDir := a.Cfg.Conf.BaseConfig().PublishDir if !ok {
return nil, fmt.Errorf("expected pageSubset, got %T", ctx.Document)
if destinationDir == "" {
a.Cfg.Logger.Errorln("markup.asciidocext.workingFolderCurrent requires hugo command option --destination to be set")
} }
var outDir string // Derive the outdir document attribute from the relative permalink.
var err error relPath := strings.TrimPrefix(page.RelPermalink(), a.Cfg.Conf.BaseURL().BasePathNoTrailingSlash)
relPath, err := url.PathUnescape(relPath)
if err != nil {
return nil, err
}
file := filepath.Base(ctx.Filename) if a.Cfg.Conf.IsMultihost() {
if a.Cfg.Conf.IsUglyURLs("") || file == "_index.adoc" || file == "index.adoc" { // In a multi-host configuration, neither absolute nor relative
outDir, err = filepath.Abs(filepath.Dir(filepath.Join(destinationDir, ctx.DocumentName))) // permalinks include the language key; prepend it.
} else { language, ok := a.Cfg.Conf.Language().(*langs.Language)
postDir := "" if !ok {
page, ok := ctx.Document.(pageSubset) return nil, fmt.Errorf("expected *langs.Language, got %T", a.Cfg.Conf.Language())
if ok { }
postDir = filepath.Base(page.RelPermalink()) relPath = path.Join(language.Lang, relPath)
}
if a.Cfg.Conf.IsUglyURLs(page.Section()) {
if page.IsPage() {
// Remove the extension.
relPath = strings.TrimSuffix(relPath, path.Ext(relPath))
} else { } else {
a.Cfg.Logger.Errorln("unable to cast interface to pageSubset") // Remove the file name.
relPath = path.Dir(relPath)
} }
outDir, err = filepath.Abs(filepath.Join(destinationDir, filepath.Dir(ctx.DocumentName), postDir)) // Set imagesoutdir and imagesdir attributes.
} imagesoutdir, err := filepath.Abs(filepath.Join(a.Cfg.Conf.BaseConfig().PublishDir, relPath))
if err != nil {
return nil, err
}
imagesdir := filepath.Base(imagesoutdir)
if page.IsPage() {
args = append(args, "-a", "imagesoutdir="+imagesoutdir, "-a", "imagesdir="+imagesdir)
} else {
args = append(args, "-a", "imagesoutdir="+imagesoutdir)
}
}
// Prepend the publishDir.
outDir, err := filepath.Abs(filepath.Join(a.Cfg.Conf.BaseConfig().PublishDir, relPath))
if err != nil { if err != nil {
a.Cfg.Logger.Errorln("asciidoctor outDir: ", err) return nil, err
} }
args = append(args, "--base-dir", contentDir, "-a", "outdir="+outDir) args = append(args, "--base-dir", filepath.Dir(ctx.Filename), "-a", "outdir="+outDir)
} }
if cfg.NoHeaderOrFooter { if cfg.NoHeaderOrFooter {
args = append(args, "--no-header-footer") args = append(args, "--no-header-footer")
} else { } else {
a.Cfg.Logger.Warnln("asciidoctor parameter NoHeaderOrFooter is expected for correct html rendering") a.Cfg.Logger.Warnln("Asciidoctor parameter NoHeaderOrFooter is required for correct HTML rendering")
} }
if cfg.SectionNumbers { if cfg.SectionNumbers {
@@ -159,29 +242,71 @@ func (a *AsciidocConverter) ParseArgs(ctx converter.DocumentContext) []string {
args = a.AppendArg(args, "--safe-mode", cfg.SafeMode, asciidocext_config.CliDefault.SafeMode, asciidocext_config.AllowedSafeMode) args = a.AppendArg(args, "--safe-mode", cfg.SafeMode, asciidocext_config.CliDefault.SafeMode, asciidocext_config.AllowedSafeMode)
return args return args, nil
} }
func (a *AsciidocConverter) AppendArg(args []string, option, value, defaultValue string, allowedValues map[string]bool) []string { func (a *AsciiDocConverter) AppendArg(args []string, option, value, defaultValue string, allowedValues map[string]bool) []string {
if value != defaultValue { if value != defaultValue {
if allowedValues[value] { if allowedValues[value] {
args = append(args, option, value) args = append(args, option, value)
} else { } else {
a.Cfg.Logger.Errorln("Unsupported asciidoctor value `" + value + "` for option " + option + " was passed in and will be ignored.") a.Cfg.Logger.Errorf(
"Unsupported Asciidoctor value %q for option %q was passed in and will be ignored.",
value,
option,
)
} }
} }
return args return args
} }
const asciiDocBinaryName = "asciidoctor" // HasAsciiDoc reports whether the AsciiDoc converter is installed.
func HasAsciiDoc() (bool, error) {
if !hexec.InPath(asciiDocBinaryName) {
return false, fmt.Errorf("the AsciiDoc converter (%s) is not installed", asciiDocBinaryName)
}
return true, nil
}
func HasAsciiDoc() bool { // CanRenderGoATDiagrams reports whether the AsciiDoc converter can render
return hexec.InPath(asciiDocBinaryName) // GoAT diagrams. Only used in tests.
func CanRenderGoATDiagrams() (bool, error) {
// Verify that the AsciiDoc converter is installed.
if ok, err := HasAsciiDoc(); !ok {
return false, err
}
// Verify that the RubyGems CLI is installed.
if !hexec.InPath(gemBinaryName) {
return false, fmt.Errorf("the RubyGems CLI (%s) is not installed", gemBinaryName)
}
// Verify that the required AsciiDoc converter extension is installed.
sc := security.DefaultConfig
sc.Exec.Allow = security.MustNewWhitelist(gemBinaryName)
ex := hexec.New(sc, "", loggers.NewDefault())
args := []any{"list", asciiDocDiagramExtension, "--installed"}
cmd, err := ex.New(gemBinaryName, args...)
if err != nil {
return false, err
}
err = cmd.Run()
if err != nil {
return false, fmt.Errorf("the %s gem is not installed", asciiDocDiagramExtension)
}
// Verify that the GoAT CLI is installed.
if !hexec.InPath(goatBinaryName) {
return false, fmt.Errorf("the GoAT CLI (%s) is not installed", goatBinaryName)
}
return true, nil
} }
// extractTOC extracts the toc from the given src html. // extractTOC extracts the toc from the given src html.
// It returns the html without the TOC, and the TOC data // It returns the html without the TOC, and the TOC data
func (a *AsciidocConverter) extractTOC(src []byte) ([]byte, *tableofcontents.Fragments, error) { func (a *AsciiDocConverter) extractTOC(src []byte) ([]byte, *tableofcontents.Fragments, error) {
var buf bytes.Buffer var buf bytes.Buffer
buf.Write(src) buf.Write(src)
node, err := html.Parse(&buf) node, err := html.Parse(&buf)
@@ -196,7 +321,7 @@ func (a *AsciidocConverter) extractTOC(src []byte) ([]byte, *tableofcontents.Fra
f = func(n *html.Node) bool { f = func(n *html.Node) bool {
if n.Type == html.ElementNode && n.Data == "div" && attr(n, "id") == "toc" { if n.Type == html.ElementNode && n.Data == "div" && attr(n, "id") == "toc" {
toc = parseTOC(n) toc = parseTOC(n)
if !a.Cfg.MarkupConfig().AsciidocExt.PreserveTOC { if !a.Cfg.MarkupConfig().AsciiDocExt.PreserveTOC {
n.Parent.RemoveChild(n) n.Parent.RemoveChild(n)
} }
return true return true
+3 -3
View File
@@ -37,8 +37,8 @@ type Config struct {
// Configuration for the Goldmark markdown engine. // Configuration for the Goldmark markdown engine.
Goldmark goldmark_config.Config Goldmark goldmark_config.Config
// Configuration for the Asciidoc external markdown engine. // Configuration for the AsciiDoc external markdown engine.
AsciidocExt asciidocext_config.Config AsciiDocExt asciidocext_config.Config
} }
func (c *Config) Init() error { func (c *Config) Init() error {
@@ -118,5 +118,5 @@ var Default = Config{
Highlight: highlight.DefaultConfig, Highlight: highlight.DefaultConfig,
Goldmark: goldmark_config.Default, Goldmark: goldmark_config.Default,
AsciidocExt: asciidocext_config.Default, AsciiDocExt: asciidocext_config.Default,
} }
+2 -2
View File
@@ -48,8 +48,8 @@ func TestConfig(t *testing.T) {
c.Assert(conf.Goldmark.Parser.Attribute.Title, qt.Equals, true) c.Assert(conf.Goldmark.Parser.Attribute.Title, qt.Equals, true)
c.Assert(conf.Goldmark.Parser.Attribute.Block, qt.Equals, false) c.Assert(conf.Goldmark.Parser.Attribute.Block, qt.Equals, false)
c.Assert(conf.AsciidocExt.WorkingFolderCurrent, qt.Equals, true) c.Assert(conf.AsciiDocExt.WorkingFolderCurrent, qt.Equals, true)
c.Assert(conf.AsciidocExt.Extensions[0], qt.Equals, "asciidoctor-html5s") c.Assert(conf.AsciiDocExt.Extensions[0], qt.Equals, "asciidoctor-html5s")
}) })
// We changed the typographer extension config from a bool to a struct in 0.112.0. // We changed the typographer extension config from a bool to a struct in 0.112.0.
@@ -297,10 +297,10 @@ Summary Truncated: {{ .Truncated }}|
) )
} }
func TestPageMarkupWithoutSummaryAsciidoc(t *testing.T) { func TestPageMarkupWithoutSummaryAsciiDoc(t *testing.T) {
t.Parallel() t.Parallel()
if !asciidocext.Supports() { if ok, err := asciidocext.Supports(); !ok {
t.Skip("Skip asiidoc test as not supported") t.Skip(err)
} }
files := ` files := `