diff --git a/libasciidoc.go b/libasciidoc.go
index 34a9d750..6e9deb2b 100644
--- a/libasciidoc.go
+++ b/libasciidoc.go
@@ -15,7 +15,7 @@ import (
// ConvertToHTMLBody converts the content of the given reader `r` into an set of
elements for an HTML/BODY document.
// The conversion result is written in the given writer `w`, whereas the document metadata (title, etc.) (or an error if a problem occurred) is returned
// as the result of the function call.
-func ConvertToHTMLBody(r io.Reader, w io.Writer) (*types.DocumentMetadata, error) {
+func ConvertToHTMLBody(r io.Reader, w io.Writer) (*types.DocumentAttributes, error) {
doc, err := parser.ParseReader("", r)
if err != nil {
return nil, errors.Wrapf(err, "error while parsing the document")
@@ -28,7 +28,7 @@ func ConvertToHTMLBody(r io.Reader, w io.Writer) (*types.DocumentMetadata, error
return nil, errors.Wrapf(err, "error while rendering the document")
}
log.Debugf("Done processing document")
- return document.Metadata, nil
+ return document.Attributes, nil
}
// ConvertToHTML converts the content of the given reader `r` into a full HTML document, written in the given writer `w`.
diff --git a/parser/asciidoc-grammar.peg b/parser/asciidoc-grammar.peg
index 2f649604..5338c134 100644
--- a/parser/asciidoc-grammar.peg
+++ b/parser/asciidoc-grammar.peg
@@ -17,7 +17,7 @@ DocumentBlock <- !EOF content:(Section / StandaloneBlock) {
return content.(types.DocElement), nil
}
-StandaloneBlock <- List / BlockImage / DelimitedBlock / Paragraph / MetadataElement / BlankLine
+StandaloneBlock <- DocumentAttribute / List / BlockImage / DelimitedBlock / Paragraph / ElementAttribute / BlankLine //TODO: should Paragraph be the last type ?
Section <- Section1 / Section2 / Section3 / Section4 / Section5 / Section6
@@ -75,37 +75,51 @@ Section6Block <- !Section1 !Section2 !Section3 !Section4 !Section5 !Section6 con
// ------------------------------------------
Heading <- Heading1 / Heading2 / Heading3 / Heading4 / Heading5 / Heading6
-Heading1 <- metadata:(MetadataElement)* level:("=") WS+ content:InlineContent (BlankLine? / EOF) {
- return types.NewHeading(1, content.(*types.InlineContent), metadata.([]interface{}))
+Heading1 <- attributes:(ElementAttribute)* level:("=") WS+ content:InlineContent (BlankLine? / EOF) { //TODO: replace `(BlankLine? / EOF)` with `EOL` to allow for immediate attributes or any other content ?
+ return types.NewHeading(1, content.(*types.InlineContent), attributes.([]interface{}))
}
-Heading2 <- metadata:(MetadataElement)* level:("==") WS+ content:InlineContent (BlankLine? / EOF) {
- return types.NewHeading(2, content.(*types.InlineContent), metadata.([]interface{}))
+Heading2 <- attributes:(ElementAttribute)* level:("==") WS+ content:InlineContent (BlankLine? / EOF) {
+ return types.NewHeading(2, content.(*types.InlineContent), attributes.([]interface{}))
}
-Heading3 <- metadata:(MetadataElement)* level:("===") WS+ content:InlineContent (BlankLine? / EOF) {
- return types.NewHeading(3, content.(*types.InlineContent), metadata.([]interface{}))
+Heading3 <- attributes:(ElementAttribute)* level:("===") WS+ content:InlineContent (BlankLine? / EOF) {
+ return types.NewHeading(3, content.(*types.InlineContent), attributes.([]interface{}))
}
-Heading4 <- metadata:(MetadataElement)* level:("====") WS+ content:InlineContent (BlankLine? / EOF) {
- return types.NewHeading(4, content.(*types.InlineContent), metadata.([]interface{}))
+Heading4 <- attributes:(ElementAttribute)* level:("====") WS+ content:InlineContent (BlankLine? / EOF) {
+ return types.NewHeading(4, content.(*types.InlineContent), attributes.([]interface{}))
}
-Heading5 <- metadata:(MetadataElement)* level:("=====") WS+ content:InlineContent (BlankLine? / EOF) {
- return types.NewHeading(5, content.(*types.InlineContent), metadata.([]interface{}))
+Heading5 <- attributes:(ElementAttribute)* level:("=====") WS+ content:InlineContent (BlankLine? / EOF) {
+ return types.NewHeading(5, content.(*types.InlineContent), attributes.([]interface{}))
}
-Heading6 <- metadata:(MetadataElement)* level:("======") WS+ content:InlineContent (BlankLine? / EOF) {
- return types.NewHeading(6, content.(*types.InlineContent), metadata.([]interface{}))
+Heading6 <- attributes:(ElementAttribute)* level:("======") WS+ content:InlineContent (BlankLine? / EOF) {
+ return types.NewHeading(6, content.(*types.InlineContent), attributes.([]interface{}))
+}
+
+
+// ------------------------------------------
+// Document Attribute
+// ------------------------------------------
+DocumentAttribute <- DocumentAttributeWithNameOnly / DocumentAttributeWithNameAndValue
+
+DocumentAttributeWithNameOnly <- ":" name:((!NEWLINE !":" !WS .)+) ":" WS* EOL {
+ return types.NewDocumentAttribute(name.([]interface{}), nil)
+}
+
+DocumentAttributeWithNameAndValue <- ":" name:((!NEWLINE !":" !WS .)+) ":" WS+ value:(!NEWLINE .)* EOL {
+ return types.NewDocumentAttribute(name.([]interface{}), value.([]interface{}))
}
// ------------------------------------------
// List Items
// ------------------------------------------
-List <- metadata:(MetadataElement)*
+List <- attributes:(ElementAttribute)*
// list items can be followed by an optional, single blank line
elements:(ListItem BlankLine?)+ {
- return types.NewList(elements.([]interface{}), metadata.([]interface{}))
+ return types.NewList(elements.([]interface{}), attributes.([]interface{}))
}
ListItem <- WS* level:('*'+ / '-') WS+ content:(ListItemContent) {
@@ -119,8 +133,8 @@ ListItemContent <- lines:(!(WS* ('*'+ / '-') WS+) InlineContent)+ {
// Paragraphs
// ------------------------------------------
// a paragraph is a group of line ending with a blank line (or end of file)
-Paragraph <- metadata:(MetadataElement)* lines:(InlineContent)+ {
- return types.NewParagraph(c.text, lines.([]interface{}), metadata.([]interface{}))
+Paragraph <- attributes:(ElementAttribute)* lines:(InlineContent)+ {
+ return types.NewParagraph(c.text, lines.([]interface{}), attributes.([]interface{}))
}
// an inline content element may begin and end with spaces,
@@ -166,9 +180,9 @@ ExternalLink <- url:(URL_SCHEME URL) text:('[' (URL_TEXT)* ']')? {
// ------------------------------------------
// Images
// ------------------------------------------
-BlockImage <- metadata:(MetadataElement)* image:BlockImageMacro WS* EOL {
+BlockImage <- attributes:(ElementAttribute)* image:BlockImageMacro WS* EOL {
// here we can ignore the blank line in the returned element
- return types.NewBlockImage(c.text, *image.(*types.ImageMacro), metadata.([]interface{}))
+ return types.NewBlockImage(c.text, *image.(*types.ImageMacro), attributes.([]interface{}))
}
BlockImageMacro <- "image::" path:(URL) '[' attributes:(URL_TEXT?) ']' {
@@ -201,7 +215,7 @@ SourceBlockLine <- (!EOL .)* NEWLINE
// ------------------------------------------
// Meta Elements
// ------------------------------------------
-MetadataElement <- meta:(ElementLink / ElementID / ElementTitle)
+ElementAttribute <- meta:(ElementLink / ElementID / ElementTitle)
// a link attached to an element, such as a BlockImage
ElementLink <- "[" WS* "link" WS* "=" WS* path:URL WS* "]" EOL {
diff --git a/parser/asciidoc_parser_test.go b/parser/asciidoc_parser_test.go
index 36c72906..75be1356 100644
--- a/parser/asciidoc_parser_test.go
+++ b/parser/asciidoc_parser_test.go
@@ -21,7 +21,7 @@ var _ = Describe("Parsing content", func() {
"\n" +
"a paragraph with *bold content*"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{
+ Attributes: &types.DocumentAttributes{
"title": "a heading",
},
Elements: []types.DocElement{
@@ -85,7 +85,6 @@ func verify(t GinkgoTInterface, expectedDocument *types.Document, content string
}
require.Nil(t, err)
actualDocument := result.(*types.Document)
- t.Logf("actual document structure: %+v", actualDocument.Elements)
t.Logf("actual document: `%s`", actualDocument.String(0))
t.Logf("expected document: `%s`", expectedDocument.String(0))
assert.EqualValues(t, *expectedDocument, *actualDocument)
diff --git a/parser/blank_line_test.go b/parser/blank_line_test.go
index 335d43a0..62faec0d 100644
--- a/parser/blank_line_test.go
+++ b/parser/blank_line_test.go
@@ -11,7 +11,7 @@ var _ = Describe("Blank lines", func() {
second paragraph`
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -43,7 +43,7 @@ second paragraph`
second paragraph
`
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
diff --git a/parser/delimited_block_test.go b/parser/delimited_block_test.go
index 62def971..d0e4fc5d 100644
--- a/parser/delimited_block_test.go
+++ b/parser/delimited_block_test.go
@@ -11,7 +11,7 @@ var _ = Describe("Delimited Blocks", func() {
content := "some source code"
actualContent := "```\n" + content + "\n```"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.DelimitedBlock{
Kind: types.SourceBlock,
@@ -26,7 +26,7 @@ var _ = Describe("Delimited Blocks", func() {
content := "some source code\nwith an empty line\n\nin the middle"
actualContent := "```\n" + content + "\n```"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.DelimitedBlock{
Kind: types.SourceBlock,
@@ -41,7 +41,7 @@ var _ = Describe("Delimited Blocks", func() {
content := ""
actualContent := "```\n" + content + "```"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.DelimitedBlock{
Kind: types.SourceBlock,
diff --git a/parser/document_attributes_test.go b/parser/document_attributes_test.go
new file mode 100644
index 00000000..d471c315
--- /dev/null
+++ b/parser/document_attributes_test.go
@@ -0,0 +1,205 @@
+package parser_test
+
+import (
+ "github.com/bytesparadise/libasciidoc/types"
+ . "github.com/onsi/ginkgo"
+)
+
+var _ = Describe("Parsing Document Attributes", func() {
+
+ Context("Valid document attributes", func() {
+
+ It("heading section with attributes", func() {
+
+ actualContent := `= a heading
+:toc:
+:date: 2017-01-01
+:author: Xavier
+
+a paragraph`
+ expectedDocument := &types.Document{
+ Attributes: &types.DocumentAttributes{
+ "title": "a heading",
+ },
+ Elements: []types.DocElement{
+ &types.Section{
+ Heading: types.Heading{
+ Level: 1,
+ Content: &types.InlineContent{
+ Elements: []types.InlineElement{
+ &types.StringElement{Content: "a heading"},
+ },
+ },
+ ID: &types.ElementID{
+ Value: "_a_heading",
+ },
+ },
+ Elements: []types.DocElement{
+ &types.DocumentAttribute{Name: "toc"},
+ &types.DocumentAttribute{Name: "date", Value: "2017-01-01"},
+ &types.DocumentAttribute{Name: "author", Value: "Xavier"},
+ &types.Paragraph{
+ Lines: []*types.InlineContent{
+ &types.InlineContent{
+ Elements: []types.InlineElement{
+ &types.StringElement{Content: "a paragraph"},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+ verify(GinkgoT(), expectedDocument, actualContent)
+ })
+
+ It("attributes and paragraph without blank line in-between", func() {
+
+ actualContent := `:toc:
+:date: 2017-01-01
+:author: Xavier
+a paragraph`
+ expectedDocument := &types.Document{
+ Attributes: &types.DocumentAttributes{},
+ Elements: []types.DocElement{
+ &types.DocumentAttribute{Name: "toc"},
+ &types.DocumentAttribute{Name: "date", Value: "2017-01-01"},
+ &types.DocumentAttribute{Name: "author", Value: "Xavier"},
+ &types.Paragraph{
+ Lines: []*types.InlineContent{
+ &types.InlineContent{
+ Elements: []types.InlineElement{
+ &types.StringElement{Content: "a paragraph"},
+ },
+ },
+ },
+ },
+ },
+ }
+ verify(GinkgoT(), expectedDocument, actualContent)
+ })
+
+ It("contiguous attributes and paragraph with blank line in-between", func() {
+
+ actualContent := `:toc:
+:date: 2017-01-01
+:author: Xavier
+
+a paragraph`
+ expectedDocument := &types.Document{
+ Attributes: &types.DocumentAttributes{},
+ Elements: []types.DocElement{
+ &types.DocumentAttribute{Name: "toc"},
+ &types.DocumentAttribute{Name: "date", Value: "2017-01-01"},
+ &types.DocumentAttribute{Name: "author", Value: "Xavier"},
+ &types.Paragraph{
+ Lines: []*types.InlineContent{
+ &types.InlineContent{
+ Elements: []types.InlineElement{
+ &types.StringElement{Content: "a paragraph"},
+ },
+ },
+ },
+ },
+ },
+ }
+ verify(GinkgoT(), expectedDocument, actualContent)
+ })
+
+ It("splitted attributes and paragraph with blank line in-between", func() {
+
+ actualContent := `:toc:
+:date: 2017-01-01
+
+:author: Xavier
+
+a paragraph`
+ expectedDocument := &types.Document{
+ Attributes: &types.DocumentAttributes{},
+ Elements: []types.DocElement{
+ &types.DocumentAttribute{Name: "toc"},
+ &types.DocumentAttribute{Name: "date", Value: "2017-01-01"},
+ &types.DocumentAttribute{Name: "author", Value: "Xavier"},
+ &types.Paragraph{
+ Lines: []*types.InlineContent{
+ &types.InlineContent{
+ Elements: []types.InlineElement{
+ &types.StringElement{Content: "a paragraph"},
+ },
+ },
+ },
+ },
+ },
+ }
+ verify(GinkgoT(), expectedDocument, actualContent)
+ })
+
+ It("no heading and attributes in body", func() {
+
+ actualContent := `a paragraph
+
+:toc:
+:date: 2017-01-01
+:author: Xavier`
+ expectedDocument := &types.Document{
+ Attributes: &types.DocumentAttributes{},
+ Elements: []types.DocElement{
+ &types.Paragraph{
+ Lines: []*types.InlineContent{
+ &types.InlineContent{
+ Elements: []types.InlineElement{
+ &types.StringElement{Content: "a paragraph"},
+ },
+ },
+ },
+ },
+ &types.DocumentAttribute{Name: "toc"},
+ &types.DocumentAttribute{Name: "date", Value: "2017-01-01"},
+ &types.DocumentAttribute{Name: "author", Value: "Xavier"},
+ },
+ }
+ verify(GinkgoT(), expectedDocument, actualContent)
+ })
+ })
+
+ Context("Valid document attributes", func() {
+ It("paragraph and without blank line in between", func() {
+
+ actualContent := `a paragraph
+:toc:
+:date: 2017-01-01
+:author: Xavier`
+ expectedDocument := &types.Document{
+ Attributes: &types.DocumentAttributes{},
+ Elements: []types.DocElement{
+ &types.Paragraph{
+ Lines: []*types.InlineContent{
+ &types.InlineContent{
+ Elements: []types.InlineElement{
+ &types.StringElement{Content: "a paragraph"},
+ },
+ },
+ &types.InlineContent{
+ Elements: []types.InlineElement{
+ &types.StringElement{Content: ":toc:"},
+ },
+ },
+ &types.InlineContent{
+ Elements: []types.InlineElement{
+ &types.StringElement{Content: ":date: 2017-01-01"},
+ },
+ },
+ &types.InlineContent{
+ Elements: []types.InlineElement{
+ &types.StringElement{Content: ":author: Xavier"},
+ },
+ },
+ },
+ },
+ },
+ }
+ verify(GinkgoT(), expectedDocument, actualContent)
+ })
+ })
+})
diff --git a/parser/external_link_test.go b/parser/external_link_test.go
index 767dd674..b85493c7 100644
--- a/parser/external_link_test.go
+++ b/parser/external_link_test.go
@@ -10,7 +10,7 @@ var _ = Describe("External Links", func() {
It("external link", func() {
actualContent := "a link to https://foo.bar"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -32,7 +32,7 @@ var _ = Describe("External Links", func() {
It("external link with empty text", func() {
actualContent := "a link to https://foo.bar[]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -55,7 +55,7 @@ var _ = Describe("External Links", func() {
It("external link with text", func() {
actualContent := "a link to mailto:foo@bar[the foo@bar email]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
diff --git a/parser/image_test.go b/parser/image_test.go
index 42e3a6a6..ea5d0357 100644
--- a/parser/image_test.go
+++ b/parser/image_test.go
@@ -12,7 +12,7 @@ var _ = Describe("Images", func() {
It("block image with empty alt", func() {
actualContent := "image::images/foo.png[]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.BlockImage{
Macro: types.ImageMacro{
@@ -28,7 +28,7 @@ var _ = Describe("Images", func() {
It("block image with empty alt and trailing spaces", func() {
actualContent := "image::images/foo.png[] \t\t "
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.BlockImage{
Macro: types.ImageMacro{
@@ -46,7 +46,7 @@ var _ = Describe("Images", func() {
actualContent := `image::images/foo.png[]
`
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.BlockImage{
Macro: types.ImageMacro{
@@ -64,7 +64,7 @@ var _ = Describe("Images", func() {
actualContent := `image::images/foo.png[]
`
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.BlockImage{
Macro: types.ImageMacro{
@@ -83,7 +83,7 @@ var _ = Describe("Images", func() {
`
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.BlockImage{
Macro: types.ImageMacro{
@@ -101,7 +101,7 @@ var _ = Describe("Images", func() {
It("block image with alt", func() {
actualContent := "image::images/foo.png[the foo.png image]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.BlockImage{
Macro: types.ImageMacro{
@@ -122,7 +122,7 @@ var _ = Describe("Images", func() {
width := "600"
height := "400"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.BlockImage{
Macro: types.ImageMacro{
@@ -144,7 +144,7 @@ var _ = Describe("Images", func() {
It("block image appending inline content", func() {
actualContent := "a paragraph\nimage::images/foo.png[]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -173,7 +173,7 @@ var _ = Describe("Images", func() {
It("inline image with empty alt", func() {
actualContent := "image:images/foo.png[]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -197,7 +197,7 @@ var _ = Describe("Images", func() {
It("inline image with empty alt and trailing spaces", func() {
actualContent := "image:images/foo.png[] \t\t "
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -224,7 +224,7 @@ var _ = Describe("Images", func() {
It("inline image surrounded with test", func() {
actualContent := "a foo image:images/foo.png[] bar..."
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -254,7 +254,7 @@ var _ = Describe("Images", func() {
It("inline image with alt", func() {
actualContent := "image:images/foo.png[the foo.png image]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -279,7 +279,7 @@ var _ = Describe("Images", func() {
It("inline image appending inline content", func() {
actualContent := "a paragraph\nimage::images/foo.png[]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
diff --git a/parser/list_test.go b/parser/list_test.go
index e7597c29..87447795 100644
--- a/parser/list_test.go
+++ b/parser/list_test.go
@@ -12,7 +12,7 @@ var _ = Describe("List Items", func() {
It("1 list with a single item", func() {
actualContent := "* a list item"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.List{
Items: []*types.ListItem{
@@ -38,7 +38,7 @@ var _ = Describe("List Items", func() {
actualContent := "[#listID]\n" +
"* a list item"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.List{
ID: &types.ElementID{Value: "listID"},
@@ -66,7 +66,7 @@ var _ = Describe("List Items", func() {
actualContent := "* a first item\n" +
"* a second item with *bold content*"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.List{
Items: []*types.ListItem{
@@ -109,7 +109,7 @@ var _ = Describe("List Items", func() {
actualContent := "- a first item\n" +
"- a second item with *bold content*"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.List{
Items: []*types.ListItem{
@@ -154,7 +154,7 @@ var _ = Describe("List Items", func() {
"\n" +
"* a second item with *bold content*"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.List{
Items: []*types.ListItem{
@@ -199,7 +199,7 @@ var _ = Describe("List Items", func() {
"* item 2\n" +
"on 2 lines, too."
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.List{
Items: []*types.ListItem{
@@ -250,7 +250,7 @@ var _ = Describe("List Items", func() {
"\n" +
"* an item in the second list"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.List{
Items: []*types.ListItem{
@@ -303,7 +303,7 @@ var _ = Describe("List Items", func() {
"* item 2\n" +
"** item 2.1\n"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.List{
Items: []*types.ListItem{
@@ -432,7 +432,7 @@ var _ = Describe("List Items", func() {
"** item 1.2\n" +
"* item 2"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.List{
Items: []*types.ListItem{
@@ -514,7 +514,7 @@ var _ = Describe("List Items", func() {
It("invalid list item", func() {
actualContent := "*an invalid list item"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
diff --git a/parser/meta_elements_test.go b/parser/meta_elements_test.go
index c7878986..b0a8f4fb 100644
--- a/parser/meta_elements_test.go
+++ b/parser/meta_elements_test.go
@@ -12,7 +12,7 @@ var _ = Describe("Meta Elements", func() {
It("element link alone", func() {
actualContent := "[link=http://foo.bar]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.ElementLink{Path: "http://foo.bar"},
},
@@ -23,7 +23,7 @@ var _ = Describe("Meta Elements", func() {
It("element link with spaces", func() {
actualContent := "[ link = http://foo.bar ]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.ElementLink{Path: "http://foo.bar"},
},
@@ -34,7 +34,7 @@ var _ = Describe("Meta Elements", func() {
It("element link invalid", func() {
actualContent := "[ link = http://foo.bar"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -57,7 +57,7 @@ var _ = Describe("Meta Elements", func() {
It("element id", func() {
actualContent := "[#img-foobar]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.ElementID{Value: "img-foobar"},
},
@@ -68,7 +68,7 @@ var _ = Describe("Meta Elements", func() {
It("element id with spaces", func() {
actualContent := "[ #img-foobar ]"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.ElementID{Value: "img-foobar"},
},
@@ -79,7 +79,7 @@ var _ = Describe("Meta Elements", func() {
It("element id invalid", func() {
actualContent := "[#img-foobar"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -96,7 +96,7 @@ var _ = Describe("Meta Elements", func() {
It("element title", func() {
actualContent := ".a title"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.ElementTitle{Value: "a title"},
},
@@ -107,7 +107,7 @@ var _ = Describe("Meta Elements", func() {
It("element title invalid1", func() {
actualContent := ". a title"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -122,7 +122,7 @@ var _ = Describe("Meta Elements", func() {
It("element title invalid2", func() {
actualContent := "!a title"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
diff --git a/parser/paragraph_test.go b/parser/paragraph_test.go
index e350393c..3bc24a00 100644
--- a/parser/paragraph_test.go
+++ b/parser/paragraph_test.go
@@ -10,7 +10,7 @@ var _ = Describe("Paragraphs", func() {
It("paragraph with 1 word", func() {
actualContent := "hello"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -29,7 +29,7 @@ var _ = Describe("Paragraphs", func() {
It("paragraph with few words", func() {
actualContent := "a paragraph with some content"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -48,7 +48,7 @@ var _ = Describe("Paragraphs", func() {
It("paragraph with bold content", func() {
actualContent := "a paragraph with *some bold content*"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -75,7 +75,7 @@ var _ = Describe("Paragraphs", func() {
.a title
a paragraph`
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
ID: &types.ElementID{Value: "foo"},
diff --git a/parser/quoted_text_test.go b/parser/quoted_text_test.go
index c0e84650..f39a5212 100644
--- a/parser/quoted_text_test.go
+++ b/parser/quoted_text_test.go
@@ -10,7 +10,7 @@ var _ = Describe("Quoted Texts", func() {
It("bold text of 1 word", func() {
actualContent := "*hello*"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -34,7 +34,7 @@ var _ = Describe("Quoted Texts", func() {
It("bold text of 2 words", func() {
actualContent := "*bold content*"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -58,7 +58,7 @@ var _ = Describe("Quoted Texts", func() {
It("bold text of 3 words", func() {
actualContent := "*some bold content*"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -82,7 +82,7 @@ var _ = Describe("Quoted Texts", func() {
It("inline with bold text", func() {
actualContent := "a paragraph with *some bold content*"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -107,7 +107,7 @@ var _ = Describe("Quoted Texts", func() {
It("inline with invalid bold text1", func() {
actualContent := "a paragraph with *some bold content"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -126,7 +126,7 @@ var _ = Describe("Quoted Texts", func() {
It("inline with invalid bold text2", func() {
actualContent := "a paragraph with *some bold content *"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -145,7 +145,7 @@ var _ = Describe("Quoted Texts", func() {
It("inline with invalid bold text3", func() {
actualContent := "a paragraph with * some bold content*"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -164,7 +164,7 @@ var _ = Describe("Quoted Texts", func() {
It("italic text with3 words", func() {
actualContent := "_some italic content_"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -188,7 +188,7 @@ var _ = Describe("Quoted Texts", func() {
It("monospace text with3 words", func() {
actualContent := "`some monospace content`"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -212,7 +212,7 @@ var _ = Describe("Quoted Texts", func() {
It("italic text within bold text", func() {
actualContent := "some *bold and _italic content_ together*."
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -245,7 +245,7 @@ var _ = Describe("Quoted Texts", func() {
It("invalid italic text within bold text", func() {
actualContent := "some *bold and _italic content _ together*."
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -271,7 +271,7 @@ var _ = Describe("Quoted Texts", func() {
It("italic text within invalid bold text", func() {
actualContent := "some *bold and _italic content_ together *."
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -297,7 +297,7 @@ var _ = Describe("Quoted Texts", func() {
It("bold text within italic text", func() {
actualContent := "_some *bold* content_"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -328,7 +328,7 @@ var _ = Describe("Quoted Texts", func() {
It("monospace text within bold text within italic quote", func() {
actualContent := "*some _italic and `monospaced content`_*"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -364,7 +364,7 @@ var _ = Describe("Quoted Texts", func() {
It("italic text within italic text", func() {
actualContent := "_some _very italic_ content_"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
diff --git a/parser/section_test.go b/parser/section_test.go
index 4d848db8..55a03743 100644
--- a/parser/section_test.go
+++ b/parser/section_test.go
@@ -12,7 +12,7 @@ var _ = Describe("Sections", func() {
It("section with heading only", func() {
actualContent := "= a heading"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{
+ Attributes: &types.DocumentAttributes{
"title": "a heading",
},
Elements: []types.DocElement{
@@ -37,7 +37,7 @@ var _ = Describe("Sections", func() {
It("section level 2", func() {
actualContent := `== section 2`
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Section{
Heading: types.Heading{
@@ -61,7 +61,7 @@ var _ = Describe("Sections", func() {
It("section level 2 with quoted text", func() {
actualContent := `== *2 spaces and bold content*`
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Section{
Heading: types.Heading{
@@ -91,7 +91,7 @@ var _ = Describe("Sections", func() {
"\n" +
"== section 2"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{
+ Attributes: &types.DocumentAttributes{
"title": "a heading",
}, Elements: []types.DocElement{
&types.Section{
@@ -133,7 +133,7 @@ var _ = Describe("Sections", func() {
"\n" +
"=== section 3"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{
+ Attributes: &types.DocumentAttributes{
"title": "a heading",
},
Elements: []types.DocElement{
@@ -175,7 +175,7 @@ var _ = Describe("Sections", func() {
actualContent := `== a title
and a paragraph`
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Section{
Heading: types.Heading{
@@ -208,7 +208,7 @@ and a paragraph`
It("section level 2 with a paragraph separated by empty line", func() {
actualContent := "== a title\n\nand a paragraph"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Section{
Heading: types.Heading{
@@ -242,7 +242,7 @@ and a paragraph`
It("section level 2 with a paragraph separated by non-empty line", func() {
actualContent := "== a title\n \nand a paragraph"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Section{
Heading: types.Heading{
@@ -285,7 +285,7 @@ a paragraph
== Section B
a paragraph`
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{
+ Attributes: &types.DocumentAttributes{
"title": "a title",
},
Elements: []types.DocElement{
@@ -388,7 +388,7 @@ a paragraph`
It("heading invalid - missing space", func() {
actualContent := "=a heading"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -406,7 +406,7 @@ a paragraph`
It("heading invalid - heading space", func() {
actualContent := " = a heading"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{},
+ Attributes: &types.DocumentAttributes{},
Elements: []types.DocElement{
&types.Paragraph{
Lines: []*types.InlineContent{
@@ -426,7 +426,7 @@ a paragraph`
"\n" +
" == section 2"
expectedDocument := &types.Document{
- Metadata: &types.DocumentMetadata{
+ Attributes: &types.DocumentAttributes{
"title": "a heading",
},
Elements: []types.DocElement{
diff --git a/renderer/html5/blank_line_test.go b/renderer/html5/blank_line_test.go
index 7cbe2ba7..b18b020c 100644
--- a/renderer/html5/blank_line_test.go
+++ b/renderer/html5/blank_line_test.go
@@ -24,6 +24,16 @@ second paragraph`
`
+ verify(GinkgoT(), expected, content)
+ })
+ It("blank lines at end of document", func() {
+ content := `first paragraph
+
+
+ `
+ expected := ``
verify(GinkgoT(), expected, content)
})
diff --git a/renderer/html5/document_attribute_test.go b/renderer/html5/document_attribute_test.go
new file mode 100644
index 00000000..4c4d7ddb
--- /dev/null
+++ b/renderer/html5/document_attribute_test.go
@@ -0,0 +1,32 @@
+package html5_test
+
+import . "github.com/onsi/ginkgo"
+
+var _ = Describe("Rendering With Attributes", func() {
+ It("some attributes then a paragraph", func() {
+ content := `:toc:
+:date: 2017-01-01
+:author: Xavier
+a paragraph`
+
+ expected := ``
+ verify(GinkgoT(), expected, content)
+ })
+})
+
+var _ = Describe("Rendering With Attributes", func() {
+ It("a paragraph then some attributes", func() {
+ content := `a paragraph
+
+:toc:
+:date: 2017-01-01
+:author: Xavier`
+
+ expected := ``
+ verify(GinkgoT(), expected, content)
+ })
+})
diff --git a/renderer/html5/paragraph_test.go b/renderer/html5/paragraph_test.go
index 35820985..a9d62efd 100644
--- a/renderer/html5/paragraph_test.go
+++ b/renderer/html5/paragraph_test.go
@@ -21,6 +21,22 @@ with more content afterwards...
expected := `
a title
bold content with more content afterwards...
+
`
+ verify(GinkgoT(), expected, content)
+ })
+
+ It("2 paragraphs and blank line", func() {
+ content := `
+*bold content* with more content afterwards...
+
+and here another paragraph
+
+`
+ expected := `
+
bold content with more content afterwards...
+
+
+
and here another paragraph
`
verify(GinkgoT(), expected, content)
})
diff --git a/renderer/html5/renderer.go b/renderer/html5/renderer.go
index 24101604..7ad46339 100644
--- a/renderer/html5/renderer.go
+++ b/renderer/html5/renderer.go
@@ -10,6 +10,7 @@ import (
"github.com/bytesparadise/libasciidoc/renderer"
"github.com/bytesparadise/libasciidoc/types"
"github.com/pkg/errors"
+ log "github.com/sirupsen/logrus"
)
var documentTmpl *texttemplate.Template
@@ -59,8 +60,8 @@ func Render(ctx context.Context, document types.Document, output io.Writer, opti
renderedHTMLElements := template.HTML(renderedElementsBuff.String())
title := "undefined"
- if document.Metadata.GetTitle() != nil {
- title = *document.Metadata.GetTitle()
+ if document.Attributes.GetTitle() != nil {
+ title = *document.Attributes.GetTitle()
}
err := documentTmpl.Execute(output, struct {
Generator string
@@ -83,15 +84,23 @@ func Render(ctx context.Context, document types.Document, output io.Writer, opti
}
func renderElements(ctx context.Context, elements []types.DocElement, output io.Writer) error {
- for i, element := range elements {
+ hasContent := false
+ for _, element := range elements {
content, err := renderElement(ctx, element)
if err != nil {
return errors.Wrapf(err, "failed to render the document")
}
- output.Write(content)
- if _, ok := element.(*types.BlankLine); !ok && i < len(elements)-1 {
+ // if there's already some content, we need to insert a `\n` before writing
+ // the rendering output of the current element (if application, ie, not empty)
+ if hasContent && len(content) > 0 {
+ log.Debugf("Appending '\\n' after element of type '%T'", element)
output.Write([]byte("\n"))
}
+ // if the element was rendering into 'something' (ie, not enpty result)
+ if len(content) > 0 {
+ output.Write(content)
+ hasContent = true
+ }
}
return nil
}
@@ -116,8 +125,8 @@ func renderElement(ctx context.Context, element types.DocElement) ([]byte, error
return renderInlineContent(ctx, *element.(*types.InlineContent))
case *types.StringElement:
return renderStringElement(ctx, *element.(*types.StringElement))
- case *types.BlankLine, *types.ElementID, *types.ElementLink, *types.ElementTitle:
- // ignored in the output
+ case *types.DocumentAttribute:
+ // for now, silently ignored in the output
return make([]byte, 0), nil
default:
return nil, errors.Errorf("unsupported type of element: %T", element)
diff --git a/types/document_metadata.go b/types/document_metadata.go
index dd57dfef..bc703ec3 100644
--- a/types/document_metadata.go
+++ b/types/document_metadata.go
@@ -1,21 +1,29 @@
package types
-// DocumentMetadata the document metadata
-type DocumentMetadata map[string]string
+// DocumentAttributes the document metadata
+type DocumentAttributes map[string]interface{}
const (
title string = "title"
)
// GetTitle retrieves the document title in its metadata, or returns nil if the title was not specified
-func (m DocumentMetadata) GetTitle() *string {
+func (m DocumentAttributes) GetTitle() *string {
if t, ok := m[title]; ok {
- return &t
+ if t, ok := t.(string); ok {
+ return &t
+ }
}
return nil
}
// SetTitle sets the title in the document metadata
-func (m DocumentMetadata) SetTitle(t string) {
+func (m DocumentAttributes) SetTitle(t string) {
m[title] = t
}
+
+// Add adds the given attribute
+func (m DocumentAttributes) Add(a *DocumentAttribute) {
+ // TODO: raise a warning if there was already a name/value
+ m[a.Name] = a.Value
+}
diff --git a/types/grammar_types.go b/types/grammar_types.go
index 6999685e..9b33d63e 100644
--- a/types/grammar_types.go
+++ b/types/grammar_types.go
@@ -23,11 +23,13 @@ type DocElement interface {
String(int) string
}
+// InlineElement the interface for inline elements
type InlineElement interface {
DocElement
PlainString() string
}
+// Visitable the interface for visitable elements
type Visitable interface {
Accept(Visitor) error
}
@@ -45,8 +47,8 @@ type Visitor interface {
// Document the top-level structure for a document
type Document struct {
- Metadata *DocumentMetadata
- Elements []DocElement
+ Attributes *DocumentAttributes
+ Elements []DocElement
}
// NewDocument initializes a new `Document` from the given lines
@@ -57,13 +59,13 @@ func NewDocument(blocks []interface{}) (*Document, error) {
}
elements := convertBlocksToDocElements(blocks)
document := &Document{Elements: elements}
- document.initMetadata()
+ document.initAttributes()
return document, nil
}
-// initMetadata initializes the Document's metadata
-func (d *Document) initMetadata() {
- metadata := &DocumentMetadata{}
+// initAttributes initializes the Document's attributes
+func (d *Document) initAttributes() {
+ d.Attributes = &DocumentAttributes{}
// look-up the document title in the (first) section of level 1
var headSection *Section
for _, element := range d.Elements {
@@ -74,21 +76,60 @@ func (d *Document) initMetadata() {
}
}
if headSection != nil {
- metadata.SetTitle(headSection.Heading.PlainString())
+ d.Attributes.SetTitle(headSection.Heading.PlainString())
}
- d.Metadata = metadata
+
}
// String implements the DocElement#String() method
func (d *Document) String(indentLevel int) string {
- log.Debugf("Printing document...")
result := bytes.NewBuffer(make([]byte, 0))
for i := range d.Elements {
result.WriteString(fmt.Sprintf("\n%s", d.Elements[i].String(0)))
}
+ log.Debug(fmt.Sprintf("Printing document:\n%s", result.String()))
+ return result.String()
+}
+
+// ------------------------------------------
+// Document Attributes
+// ------------------------------------------
+
+// DocumentAttribute the type for Document Attributes
+type DocumentAttribute struct {
+ Name string
+ Value string
+}
+
+// NewDocumentAttribute initializes a new Document Attribute
+func NewDocumentAttribute(name []interface{}, value []interface{}) (*DocumentAttribute, error) {
+ attrName, err := stringify(name)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error while initializing a DocumentAttribute")
+ }
+ attrValue, err := stringify(value)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error while initializing a DocumentAttribute")
+ }
+ log.Debugf("Initialized a new DocumentAttribute: '%s' -> '%s'", *attrName, *attrValue)
+ return &DocumentAttribute{
+ Name: *attrName,
+ Value: *attrValue,
+ }, nil
+}
+
+// String implements the DocElement#String() method
+func (a *DocumentAttribute) String(indentLevel int) string {
+ result := bytes.NewBuffer(make([]byte, 0))
+ result.WriteString(fmt.Sprintf("%s '%s' -> '%s'\n", indent(indentLevel), a.Name, a.Value))
return result.String()
}
+// Accept implements DocElement#Accept(Visitor)
+func (a *DocumentAttribute) Accept(v Visitor) error {
+ return nil
+}
+
// ------------------------------------------
// Section
// ------------------------------------------
@@ -159,11 +200,11 @@ type Heading struct {
Content *InlineContent
}
-// NewHeading initializes a new `Heading from the given level and content, with the optional metadata.
-// In the metadata, only the ElementID is retained
-func NewHeading(level int, inlineContent *InlineContent, metadata []interface{}) (*Heading, error) {
+// NewHeading initializes a new `Heading from the given level and content, with the optional attributes.
+// In the attributes, only the ElementID is retained
+func NewHeading(level int, inlineContent *InlineContent, attributes []interface{}) (*Heading, error) {
// counting the lenght of the 'level' value (ie, the number of `=` chars)
- id, _, _ := newMetaElements(metadata)
+ id, _, _ := newElementAttributes(attributes)
// make a default id from the heading's inline content
if id == nil {
replacement, err := ReplaceNonAlphanumerics(inlineContent, "_")
@@ -222,8 +263,8 @@ type List struct {
}
// NewList initializes a new `ListItem` from the given content
-func NewList(elements []interface{}, metadata []interface{}) (*List, error) {
- id, _, _ := newMetaElements(metadata)
+func NewList(elements []interface{}, attributes []interface{}) (*List, error) {
+ id, _, _ := newElementAttributes(attributes)
items := make([]*ListItem, 0)
log.Debugf("Initializing a new List from %d elements", len(elements))
currentLevel := 1
@@ -431,9 +472,9 @@ type Paragraph struct {
}
// NewParagraph initializes a new `Paragraph`
-func NewParagraph(text []byte, lines []interface{}, metadata []interface{}) (*Paragraph, error) {
+func NewParagraph(text []byte, lines []interface{}, attributes []interface{}) (*Paragraph, error) {
log.Debugf("Initializing a new Paragraph with %d line(s)", len(lines))
- id, title, _ := newMetaElements(metadata)
+ id, title, _ := newElementAttributes(attributes)
typedLines := make([]*InlineContent, 0)
for _, line := range lines {
@@ -551,9 +592,9 @@ type BlockImage struct {
}
// NewBlockImage initializes a new `BlockImage`
-func NewBlockImage(input []byte, imageMacro ImageMacro, metadata []interface{}) (*BlockImage, error) {
+func NewBlockImage(input []byte, imageMacro ImageMacro, attributes []interface{}) (*BlockImage, error) {
log.Debugf("Initializing a new BlockImage from '%s'", input)
- id, title, link := newMetaElements(metadata)
+ id, title, link := newElementAttributes(attributes)
return &BlockImage{
Macro: imageMacro,
ID: id,
@@ -600,7 +641,7 @@ type InlineImage struct {
Macro ImageMacro
}
-// NewInlineImage initializes a new `InlineImage` (similar to BlockImage, but without Metadata)
+// NewInlineImage initializes a new `InlineImage` (similar to BlockImage, but without attributes)
func NewInlineImage(input []byte, imageMacro ImageMacro) (*InlineImage, error) {
log.Debugf("Initializing a new InlineImage from '%s'", input)
return &InlineImage{
@@ -770,11 +811,11 @@ func (b *DelimitedBlock) Accept(v Visitor) error {
// Meta Elements
// ------------------------------------------
-func newMetaElements(metadata []interface{}) (*ElementID, *ElementTitle, *ElementLink) {
+func newElementAttributes(attributes []interface{}) (*ElementID, *ElementTitle, *ElementLink) {
var id *ElementID
var title *ElementTitle
var link *ElementLink
- for _, item := range metadata {
+ for _, item := range attributes {
switch item := item.(type) {
case *ElementID:
id = item
@@ -783,7 +824,7 @@ func newMetaElements(metadata []interface{}) (*ElementID, *ElementTitle, *Elemen
case *ElementTitle:
title = item
default:
- log.Warnf("Unexpected metadata: %T", item)
+ log.Warnf("Unexpected attributes: %T", item)
}
}
return id, title, link
diff --git a/types/type_utils.go b/types/type_utils.go
index eb81843e..948a41cd 100644
--- a/types/type_utils.go
+++ b/types/type_utils.go
@@ -138,15 +138,11 @@ func isMn(r rune) bool {
return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
}
-//ReplaceNonAlphanumerics replaces all non alphanumerical characters and remove (accents)
+// NewReplaceNonAlphanumericsFunc replaces all non alphanumerical characters and remove (accents)
// in the given 'source' with the given 'replacement'.
func NewReplaceNonAlphanumericsFunc(replacement string) NormalizationFunc {
return func(source string) ([]byte, error) {
buf := bytes.NewBuffer(make([]byte, 0))
- // _, err := buf.WriteString(replacement)
- // if err != nil {
- // return nil, errors.Wrapf(err, "unable to normalize value")
- // }
lastCharIsSpace := false
for _, r := range strings.TrimLeft(source, " ") { // ignore heading spaces
if unicode.Is(unicode.Letter, r) || unicode.Is(unicode.Number, r) {