Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(types/parser): parse by fragment and process in pipeline #855

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [1.15.x, 1.14.x]
go-version: [1.16.x,1.15.x]
os: [ubuntu-latest, macos-latest, windows-latest]
name: Test ${{ matrix.os }} with Go ${{ matrix.go-version }}

Expand Down
8 changes: 5 additions & 3 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,21 @@ run:
timeout: 5m

linters:
enable-all: false
enable:
- megacheck
- govet
- gocyclo
- unused
- gofmt
- golint
- revive
- misspell
enable-all: false
- exportloopref
disable-all: false
disable:
- maligned
- prealloc
disable-all: false
- scopelint
presets:
- bugs
- unused
Expand Down
4 changes: 2 additions & 2 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ Libasciidoc provides 2 functions to convert an Asciidoc content into HTML:

1. Converting an `io.Reader` into an HTML document:

Convert(r io.Reader, output io.Writer, config configuration.Configuration) (types.Metadata, error)
Convert(r io.Reader, output io.Writer, config *configuration.Configuration) (types.Metadata, error)

2. Converting a file (given its name) into an HTML document:

ConvertFile(output io.Writer, config configuration.Configuration) (types.Metadata, error)
ConvertFile(output io.Writer, config *configuration.Configuration) (types.Metadata, error)

where the returned `types.Metadata` object contains the document's title which is not part of the generated HTML `<body>` part, as well as the other attributes of the source document.

Expand Down
5 changes: 2 additions & 3 deletions cmd/libasciidoc/root_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ func NewRootCmd() *cobra.Command {
out, close := getOut(cmd, sourcePath, outputName)
if out != nil {
defer close() //nolint errcheck
// path, _ := filepath.Abs(sourcePath)
// log.Debugf("Starting to process file %v", path)
config := configuration.NewConfiguration(
configuration.WithFilename(sourcePath),
Expand Down Expand Up @@ -119,8 +118,8 @@ func getOut(cmd *cobra.Command, sourcePath, outputName string) (io.Writer, close
}

// converts the `name`, `!name` and `name=value` into a map
func parseAttributes(attributes []string) map[string]string {
result := make(map[string]string, len(attributes))
func parseAttributes(attributes []string) map[string]interface{} {
result := make(map[string]interface{}, len(attributes))
for _, attr := range attributes {
data := strings.Split(attr, "=")
if len(data) > 1 {
Expand Down
4 changes: 1 addition & 3 deletions cmd/libasciidoc/root_cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ var _ = Describe("root cmd", func() {
// when
err := root.Execute()
// then
GinkgoT().Logf("command output: %v", buf.String())
Expect(err).To(HaveOccurred())
})

Expand Down Expand Up @@ -93,11 +92,10 @@ var _ = Describe("root cmd", func() {
// when
err := root.Execute()
// then
GinkgoT().Logf("out: %v", buf.String())
Expect(err).ToNot(HaveOccurred())
Expect(buf.String()).ToNot(BeEmpty())
// console output also includes a warning message
Expect(buf.String()).To(Equal(`level=warning msg="unable to find attribute 'foo2'"
Expect(buf.String()).To(ContainSubstring(`level=warning msg="unable to find attribute 'foo2'"
<div class="paragraph">
<p>bar1 and {foo2}</p>
</div>
Expand Down
16 changes: 9 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,24 @@ go 1.11
require (
github.com/alecthomas/chroma v0.7.1
github.com/davecgh/go-spew v1.1.1
github.com/google/go-cmp v0.5.2 // indirect
github.com/google/go-cmp v0.5.5
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/mna/pigeon v1.0.1-0.20200224192238-18953b277063
github.com/mna/pigeon v1.1.0
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/onsi/ginkgo v1.13.0
github.com/onsi/gomega v1.10.1
github.com/onsi/ginkgo v1.16.4
github.com/onsi/gomega v1.13.0
github.com/pkg/errors v0.9.1
github.com/sergi/go-diff v1.0.0
github.com/sirupsen/logrus v1.7.0
github.com/sozorogami/gover v0.0.0-20171022184752-b58185e213c5
github.com/spf13/cobra v1.1.1
github.com/stretchr/testify v1.6.1
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 // indirect
golang.org/x/tools v0.0.0-20201013201025-64a9e34f3752 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v2 v2.3.0
gopkg.in/yaml.v2 v2.4.0
)

// include support for disabling unexported fields
// TODO: still needed?
replace github.com/davecgh/go-spew => github.com/flw-cn/go-spew v1.1.2-0.20200624141737-10fccbfd0b23
55 changes: 40 additions & 15 deletions go.sum

Large diffs are not rendered by default.

26 changes: 16 additions & 10 deletions libasciidoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var (
// ConvertFile converts the content of the given filename into an output document.
// The conversion result is written in the given writer `output`, whereas the document metadata (title, etc.) (or an error if a problem occurred) is returned
// as the result of the function call. The output format is determined by config.Backend (HTML5 default).
func ConvertFile(output io.Writer, config configuration.Configuration) (types.Metadata, error) {
func ConvertFile(output io.Writer, config *configuration.Configuration) (types.Metadata, error) {
file, err := os.Open(config.Filename)
if err != nil {
return types.Metadata{}, errors.Wrapf(err, "error opening %s", config.Filename)
Expand All @@ -50,9 +50,9 @@ func ConvertFile(output io.Writer, config configuration.Configuration) (types.Me

// Convert converts the content of the given reader `r` into a full output document, written in the given writer `output`.
// Returns an error if a problem occurred. The default will be HTML5, but depends on the config.BackEnd value.
func Convert(r io.Reader, output io.Writer, config configuration.Configuration) (types.Metadata, error) {
func Convert(r io.Reader, output io.Writer, config *configuration.Configuration) (types.Metadata, error) {

var render func(*renderer.Context, types.Document, io.Writer) (types.Metadata, error)
var render func(*renderer.Context, *types.Document, io.Writer) (types.Metadata, error)
switch config.BackEnd {
case "html", "html5", "":
render = html5.Render
Expand All @@ -73,16 +73,22 @@ func Convert(r io.Reader, output io.Writer, config configuration.Configuration)
return types.Metadata{}, err
}
// validate the document
problems, err := validator.Validate(&doc)
doctype := config.Attributes.GetAsStringWithDefault(types.AttrDocType, "article")
problems, err := validator.Validate(doc, doctype)
if err != nil {
return types.Metadata{}, err
}
for _, problem := range problems {
switch problem.Severity {
case validator.Error:
log.Error(problem.Message)
case validator.Warning:
log.Warn(problem.Message)
if len(problems) > 0 {
// if any problem found, change the doctype to render the document as a regular article
log.Warnf("changing doctype to 'article' because problems were found in the document: %v", problems)
config.Attributes[types.AttrDocType] = "article" // switch to `article` rendering (in case it was a manpage with problems)
for _, problem := range problems {
switch problem.Severity {
case validator.Error:
log.Error(problem.Message)
case validator.Warning:
log.Warn(problem.Message)
}
}
}
// render
Expand Down
128 changes: 126 additions & 2 deletions libasciidoc_bench_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,140 @@
package libasciidoc_test

import (
"strings"
"testing"

"github.com/bytesparadise/libasciidoc"
"github.com/bytesparadise/libasciidoc/pkg/configuration"
"github.com/bytesparadise/libasciidoc/pkg/types"
"github.com/bytesparadise/libasciidoc/testsupport"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func BenchmarkLibasciidoc(b *testing.B) {
// TODO: unexclude this bench func
func XBenchmarkRenderRealDocument(b *testing.B) {
filename := "./test/bench/mocking.adoc"
for i := 0; i < b.N; i++ {
_, err := testsupport.RenderHTML5Document(filename)
out := &strings.Builder{}
_, err := libasciidoc.ConvertFile(out,
configuration.NewConfiguration(
configuration.WithFilename(filename),
configuration.WithCSS("path/to/style.css"),
configuration.WithHeaderFooter(true)))
require.NoError(b, err)
}
}

func BenchmarkParseBasicDocument(b *testing.B) {
content := `== Lorem Ipsum

Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua.
At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua.
At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.`

for i := 0; i < b.N; i++ {
_, err := testsupport.ParseDocument(content)
require.NoError(b, err)
}
}

func BenchmarkParseLongDocument(b *testing.B) {
content := strings.Builder{}
for i := 0; i < 50; i++ {
content.WriteString(`== Lorem Ipsum

Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua.
At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua.
At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

`)
}
for i := 0; i < b.N; i++ {
_, err := testsupport.ParseDocument(content.String())
require.NoError(b, err)
}
}

func TestParseBasicDocument(t *testing.T) {
source := `== Lorem Ipsum

Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua.
At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua.
At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit *amet*.`

title := []interface{}{
&types.StringElement{
Content: "Lorem Ipsum",
},
}
expected := &types.Document{
Elements: []interface{}{
&types.Section{
Level: 1,
Attributes: types.Attributes{
types.AttrID: "_lorem_ipsum",
},
Title: title,
Elements: []interface{}{
&types.Paragraph{
Elements: []interface{}{
&types.StringElement{
Content: `Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua.
At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua.
At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit `,
},
&types.QuotedText{
Kind: types.SingleQuoteBold,
Elements: []interface{}{
&types.StringElement{
Content: "amet",
},
},
},
&types.StringElement{
Content: ".",
},
},
},
},
},
},
ElementReferences: types.ElementReferences{
"_lorem_ipsum": title,
},
}
result, err := testsupport.ParseDocument(source)
require.NoError(t, err)
assert.Equal(t, expected, result)

}
Loading