From dc5a36f7507ab55583b75555fd5ae50039d2818c Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Thu, 2 Jan 2020 17:29:39 +0100 Subject: [PATCH] refactor(parser): Do not retain SingleLineComments and CommentBlocks in final Document Refactor document processing to filter out all unneeded blocks in the final document, including single line comments and comment blocks also, split the `document_processing.go` file for better readability and testing also, increase testing on quoted texts and lists also, fix a problem where paragraph with empty content was not rendered at all fixes #454 Signed-off-by: Xavier Coulon --- pkg/parser/comment_test.go | 529 +- pkg/parser/document_processing.go | 493 +- ...document_processing_apply_substitutions.go | 131 + ...ent_processing_apply_substitutions_test.go | 543 ++ .../document_processing_filter_blocks.go | 123 + .../document_processing_filter_blocks_test.go | 322 + .../document_processing_rearrange_lists.go | 245 + ...ocument_processing_rearrange_lists_test.go | 423 + .../document_processing_rearrange_sections.go | 128 + ...ment_processing_rearrange_sections_test.go | 497 ++ pkg/parser/document_processing_test.go | 109 - pkg/parser/mixed_lists_test.go | 40 +- pkg/parser/ordered_list_test.go | 163 + pkg/parser/paragraph_test.go | 25 +- pkg/parser/parser.go | 1702 +++-- pkg/parser/parser.peg | 3 +- pkg/parser/quoted_text_test.go | 6804 +++++++++++++---- pkg/renderer/html5/delimited_block.go | 7 - pkg/renderer/html5/html5.go | 2 - pkg/renderer/html5/paragraph.go | 10 +- pkg/renderer/html5/paragraph_test.go | 9 + pkg/renderer/html5/passthrough_test.go | 9 +- pkg/types/element_attributes.go | 22 +- pkg/types/types.go | 16 +- pkg/types/types_utils.go | 55 - pkg/types/types_utils_test.go | 46 - 26 files changed, 9037 insertions(+), 3419 deletions(-) create mode 100644 pkg/parser/document_processing_apply_substitutions.go create mode 100644 pkg/parser/document_processing_apply_substitutions_test.go create mode 100644 pkg/parser/document_processing_filter_blocks.go create mode 100644 pkg/parser/document_processing_filter_blocks_test.go create mode 100644 pkg/parser/document_processing_rearrange_lists.go create mode 100644 pkg/parser/document_processing_rearrange_lists_test.go create mode 100644 pkg/parser/document_processing_rearrange_sections.go create mode 100644 pkg/parser/document_processing_rearrange_sections_test.go delete mode 100644 pkg/parser/document_processing_test.go diff --git a/pkg/parser/comment_test.go b/pkg/parser/comment_test.go index 10fcc301..b2b1bd79 100644 --- a/pkg/parser/comment_test.go +++ b/pkg/parser/comment_test.go @@ -8,152 +8,473 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("comments - draft", func() { +var _ = Describe("comments", func() { - Context("single line comments", func() { + Context("draft document", func() { - It("single line comment alone", func() { - source := `// A single-line comment.` - expected := types.SingleLineComment{ - Content: " A single-line comment.", - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + Context("single line comments", func() { - It("single line comment with prefixing spaces alone", func() { - source := ` // A single-line comment.` - expected := types.SingleLineComment{ - Content: " A single-line comment.", - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + It("single line comment alone", func() { + source := `// A single-line comment.` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.SingleLineComment{ + Content: " A single-line comment.", + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("single line comment with prefixing tabs alone", func() { - source := "\t\t// A single-line comment." - expected := types.SingleLineComment{ - Content: " A single-line comment.", - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + It("single line comment with prefixing spaces alone", func() { + source := ` // A single-line comment.` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.SingleLineComment{ + Content: " A single-line comment.", + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("single line comment at end of line", func() { - source := `foo // A single-line comment.` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "foo // A single-line comment."}, + It("single line comment with prefixing tabs alone", func() { + source := "\t\t// A single-line comment." + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.SingleLineComment{ + Content: " A single-line comment.", + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("single line comment within a paragraph", func() { - source := `a first line + It("single line comment at end of line", func() { + source := `foo // A single-line comment.` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "foo // A single-line comment."}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("single line comment within a paragraph", func() { + source := `a first line // A single-line comment. another line` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a first line"}, - }, - { - types.SingleLineComment{Content: " A single-line comment."}, - }, - { - types.StringElement{Content: "another line"}, + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a first line"}, + }, + { + types.SingleLineComment{Content: " A single-line comment."}, + }, + { + types.StringElement{Content: "another line"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("single line comment within a paragraph with tab", func() { - source := `a first line + It("single line comment within a paragraph with tab", func() { + source := `a first line // A single-line comment. another line` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a first line"}, - }, - { - types.SingleLineComment{Content: " A single-line comment."}, - }, - { - types.StringElement{Content: "another line"}, + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a first line"}, + }, + { + types.SingleLineComment{Content: " A single-line comment."}, + }, + { + types.StringElement{Content: "another line"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) - }) - Context("comment blocks", func() { + Context("comment blocks", func() { - It("comment block alone", func() { - source := `//// + It("comment block alone", func() { + source := `//// a *comment* block with multiple lines ////` - expected := types.DelimitedBlock{ - Attributes: types.ElementAttributes{}, - Kind: types.Comment, - Elements: []interface{}{ - types.StringElement{ - Content: "a *comment* block", + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.DelimitedBlock{ + Attributes: types.ElementAttributes{}, + Kind: types.Comment, + Elements: []interface{}{ + types.StringElement{ + Content: "a *comment* block", + }, + types.StringElement{ + Content: "with multiple lines", + }, + }, + }, }, - types.StringElement{ - Content: "with multiple lines", + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("comment block with paragraphs around", func() { + source := `a first paragraph +//// +a *comment* block +with multiple lines +//// +a second paragraph` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a first paragraph"}, + }, + }, + }, + types.DelimitedBlock{ + Attributes: types.ElementAttributes{}, + Kind: types.Comment, + Elements: []interface{}{ + types.StringElement{ + Content: "a *comment* block", + }, + types.StringElement{ + Content: "with multiple lines", + }, + }, + }, + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a second paragraph"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) + }) - It("comment block with paragraphs around", func() { - source := `a first paragraph + Context("final document", func() { + + Context("single line comments", func() { + + It("single line comment alone", func() { + source := `// A single-line comment.` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{}, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("single line comment with prefixing spaces alone", func() { + source := ` // A single-line comment.` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{}, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("single line comment with prefixing tabs alone", func() { + source := "\t\t// A single-line comment." + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{}, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("single line comment at end of line", func() { + source := `foo // A single-line comment.` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "foo // A single-line comment."}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("single line comment within a paragraph", func() { + source := `a first line +// A single-line comment. +another line` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a first line"}, + }, + { + types.StringElement{Content: "another line"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("single line comment within a paragraph with tab", func() { + source := `a first line + // A single-line comment. +another line` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a first line"}, + }, + { + types.StringElement{Content: "another line"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + + Context("comment blocks", func() { + + It("comment block alone", func() { + source := `//// +a *comment* block +with multiple lines +////` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{}, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("comment block with paragraphs around", func() { + source := `a first paragraph //// a *comment* block with multiple lines //// a second paragraph` - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a first paragraph"}, + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a first paragraph"}, + }, + }, + }, + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a second paragraph"}, + }, }, }, }, - types.DelimitedBlock{ - Attributes: types.ElementAttributes{}, - Kind: types.Comment, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + + It("comment in section", func() { + source := `== section 1 + +a first paragraph +//// +a *comment* block +with multiple lines +//// +a second paragraph` + section1Title := []interface{}{ + types.StringElement{ + Content: "section 1", + }, + } + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{ + "_section_1": section1Title, + }, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_1", + }, + Level: 1, + Title: section1Title, Elements: []interface{}{ - types.StringElement{ - Content: "a *comment* block", + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a first paragraph"}, + }, + }, }, - types.StringElement{ - Content: "with multiple lines", + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a second paragraph"}, + }, + }, }, }, }, - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a second paragraph"}, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("comment in preamble", func() { + source := `= section 0 + +//// +a *comment* block +with multiple lines +//// + +== section 1 + +a first paragraph + +a second paragraph` + section0Title := []interface{}{ + types.StringElement{ + Content: "section 0", + }, + } + section1Title := []interface{}{ + types.StringElement{ + Content: "section 1", + }, + } + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{ + "_section_0": section0Title, + "_section_1": section1Title, + }, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_0", + }, + Level: 0, + Title: section0Title, + Elements: []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_1", + }, + Level: 1, + Title: section1Title, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a first paragraph"}, + }, + }, + }, + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a second paragraph"}, + }, + }, + }, + }, }, }, }, }, } - Expect(source).To(BecomeDraftDocument(expected)) + Expect(source).To(BecomeDocument(expected)) }) }) diff --git a/pkg/parser/document_processing.go b/pkg/parser/document_processing.go index e8b4d975..666232a9 100644 --- a/pkg/parser/document_processing.go +++ b/pkg/parser/document_processing.go @@ -2,14 +2,8 @@ package parser import ( "io" - "reflect" - "strconv" - "strings" "github.com/bytesparadise/libasciidoc/pkg/types" - - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" ) // ParseDocument parses the content of the reader identitied by the filename @@ -40,15 +34,19 @@ func ParseDocument(filename string, r io.Reader, opts ...Option) (types.Document } // apply document attribute substitutions and re-parse paragraphs that were affected - blocks, err := ApplyDocumentAttributeSubstitutions(draftDoc.Blocks, attrs) + blocks, err := applyDocumentAttributeSubstitutions(draftDoc.Blocks, attrs) if err != nil { return types.Document{}, err } + // now, merge list items into proper lists blocks, err = rearrangeListItems(blocks.([]interface{}), false) if err != nil { return types.Document{}, err } + // apply document attribute substitutions and re-parse paragraphs that were affected + blocks = filter(blocks.([]interface{}), allMatchers...) + // now, rearrange elements in a hierarchical manner doc, err := rearrangeSections(blocks.([]interface{})) if err != nil { @@ -64,484 +62,3 @@ func ParseDocument(filename string, r io.Reader, opts ...Option) (types.Document } return doc, nil } - -// ApplyDocumentAttributeSubstitutions applies the document attribute substitutions -// and re-parse the paragraphs that were affected -func ApplyDocumentAttributeSubstitutions(element interface{}, attrs types.DocumentAttributes) (interface{}, error) { - // the document attributes, as they are resolved while processing the blocks - // log.Debugf("applying document substitutions on block of type %T", element) - switch e := element.(type) { - case []interface{}: - elements := make([]interface{}, 0, len(e)) // maximum capacity cannot exceed initial input - for _, element := range e { - r, err := ApplyDocumentAttributeSubstitutions(element, attrs) - if err != nil { - return []interface{}{}, err - } - elements = append(elements, r) - } - elements = types.FilterOut(elements, types.DocumentAttributeMatcher) - return parseInlineLinks(types.MergeStringElements(elements)) - case types.DocumentAttributeDeclaration: - attrs[e.Name] = e.Value - return e, nil - case types.DocumentAttributeReset: - delete(attrs, e.Name) - return e, nil - case types.DocumentAttributeSubstitution: - if value, ok := attrs[e.Name].(string); ok { - return types.StringElement{ - Content: value, - }, nil - } - return types.StringElement{ - Content: "{" + e.Name + "}", - }, nil - case types.ImageBlock: - return e.ResolveLocation(attrs), nil - case types.InlineImage: - return e.ResolveLocation(attrs), nil - case types.Section: - title, err := ApplyDocumentAttributeSubstitutions(e.Title, attrs) - if err != nil { - return struct{}{}, err - } - if title, ok := title.([]interface{}); ok { - e.Title = types.FilterOut(title, types.DocumentAttributeMatcher) - } - return e.ResolveID(attrs) - case types.OrderedListItem: - elements, err := applyDocumentAttributeSubstitutions(e.Elements, attrs) - if err != nil { - return struct{}{}, err - } - e.Elements = types.FilterOut(elements, types.DocumentAttributeMatcher) - return e, nil - case types.UnorderedListItem: - elements, err := applyDocumentAttributeSubstitutions(e.Elements, attrs) - if err != nil { - return struct{}{}, err - } - e.Elements = types.FilterOut(elements, types.DocumentAttributeMatcher) - return e, nil - case types.LabeledListItem: - elements, err := applyDocumentAttributeSubstitutions(e.Elements, attrs) - if err != nil { - return struct{}{}, err - } - e.Elements = types.FilterOut(elements, types.DocumentAttributeMatcher) - return e, nil - case types.QuotedText: - elements, err := applyDocumentAttributeSubstitutions(e.Elements, attrs) - if err != nil { - return struct{}{}, err - } - e.Elements = elements - return e, nil - case types.ContinuedListItemElement: - element, err := ApplyDocumentAttributeSubstitutions(e.Element, attrs) - if err != nil { - return struct{}{}, err - } - e.Element = element - return e, nil - case types.Paragraph: - for i, line := range e.Lines { - line, err := ApplyDocumentAttributeSubstitutions(line, attrs) - if err != nil { - return struct{}{}, err - } - e.Lines[i] = line.([]interface{}) - } - return e, nil - default: - return e, nil - } -} - -// applyDocumentAttributeSubstitutions applies the DocumentAttributeSubstitutions found in the given elements -func applyDocumentAttributeSubstitutions(elements []interface{}, attrs types.DocumentAttributes) ([]interface{}, error) { - result := make([]interface{}, len(elements)) - for j, element := range elements { - r, err := ApplyDocumentAttributeSubstitutions(element, attrs) - if err != nil { - return []interface{}{}, err - } - result[j] = r - } - return result, nil -} - -// if a document attribute substitution happened, we need to parse the string element in search -// for a potentially new link. Eg `{url}` giving `https://foo.com` -func parseInlineLinks(elements []interface{}) ([]interface{}, error) { - result := []interface{}{} - for _, element := range elements { - switch element := element.(type) { - case types.StringElement: - log.Debugf("looking for links in line element of type %[1]T (%[1]v)", element) - elements, err := ParseReader("", strings.NewReader(element.Content), Entrypoint("InlineLinks")) - if err != nil { - return []interface{}{}, errors.Wrap(err, "error while parsing content for inline links") - } - result = append(result, elements.([]interface{})...) - default: - result = append(result, element) - } - } - return result, nil -} - -// rearrangeListItems moves the list items into lists, and nested lists if needed -func rearrangeListItems(blocks []interface{}, withinDelimitedBlock bool) ([]interface{}, error) { - // log.Debugf("rearranging list items in %d blocks...", len(blocks)) - result := make([]interface{}, 0, len(blocks)) // maximum capacity cannot exceed initial input - lists := []types.List{} // at each level (or depth), we have a list, whatever its type. - blankline := false // track if the previous block was a blank line - for _, block := range blocks { - switch block := block.(type) { - case types.DelimitedBlock: - // process and replace the elements within this delimited block - elements, err := rearrangeListItems(block.Elements, true) - if err != nil { - return nil, errors.Wrapf(err, "unable to rearrange list items in delimited block") - } - block.Elements = elements - if len(lists) > 0 { - switch list := lists[0].(type) { // just add the top-level list - case *types.OrderedList: - result = append(result, *list) - case *types.UnorderedList: - result = append(result, *list) - case *types.LabeledList: - result = append(result, *list) - } - // reset the list for further usage while processing the rest of the document - lists = []types.List{} - } - result = append(result, block) - case types.OrderedListItem, types.UnorderedListItem, types.LabeledListItem: - // there's a special case: if the next list item has attributes and was preceded by a - // blank line, then we need to start a new list - if blankline && len(block.(types.DocumentElement).GetAttributes()) > 0 { - if len(lists) > 0 { - for _, list := range pruneLists(lists, 0) { - result = append(result, unPtr(list)) - } - // reset the list for further usage while processing the rest of the document - lists = []types.List{} - } - } - var err error - lists, err = appendListItem(lists, block) - if err != nil { - return nil, errors.Wrapf(err, "unable to rearrange list items in delimited block") - } - blankline = false - case types.ContinuedListItemElement: - lists = appendContinuedListItemElement(lists, block) - blankline = false - case types.BlankLine: - // blank lines are not part of the resulting Document sections (or top-level), but they are part of the delimited blocks - // in some cases, they can also be used to split lists apart (when the next item has some attributes, - // or if the next block is a comment) - if withinDelimitedBlock && len(lists) == 0 { // only retain blank lines if within a delimited block, but not currently dealing with a list (or a set of nested lists) - result = append(result, block) - } - blankline = true - default: - blankline = false - // an block which is not a list item was found. - // the first thing to do is to process the pending list items, - // then only append this block to the result - if len(lists) > 0 { - log.Debugf("appending %d lists before processing element of type %T", len(lists), block) - for _, list := range pruneLists(lists, 0) { - result = append(result, unPtr(list)) - } - // reset the list for further usage while processing the rest of the document - lists = []types.List{} - } - result = append(result, block) - } - } - // also when all is done, process the remaining pending list items - if len(lists) > 0 { - log.Debugf("processing the remaining %d lists...", len(lists)) - for _, list := range pruneLists(lists, 0) { - result = append(result, unPtr(list)) - } - } - return result, nil -} - -func unPtr(value interface{}) interface{} { - v := reflect.ValueOf(value) - k := v.Kind() - if k == reflect.Ptr && v.Elem().IsValid() { - return v.Elem().Interface() - } - return value -} - -func appendListItem(lists []types.List, item interface{}) ([]types.List, error) { - switch item := item.(type) { - case types.OrderedListItem: - return appendOrderedListItem(lists, &item) - case types.UnorderedListItem: - return appendUnorderedListItem(lists, &item) - case types.LabeledListItem: - return appendLabeledListItem(lists, item) - } - return lists, nil -} - -func appendOrderedListItem(lists []types.List, item *types.OrderedListItem) ([]types.List, error) { - maxLevel := 0 - log.Debugf("looking-up list for ordered list having items with level=%d and number style=%v", item.Level, item.NumberingStyle) - for i, list := range lists { - if list, ok := list.(*types.OrderedList); ok { - // assume we can't have empty lists - maxLevel++ - if list.Items[0].NumberingStyle == item.NumberingStyle { - log.Debugf("found a matching ordered list at level %d", list.Items[0].Level) - // prune items of "deeper/lower" level - lists = pruneLists(lists, i) - // apply the same level - item.Level = list.Items[0].Level - list.AddItem(*item) - // also, prune the pointers to the remaining sublists (in case there is any...) - return lists, nil - } - } - } - // force the current item level to (last seen level + 1) - item.Level = maxLevel + 1 - // no match found: create a new list and if needed, adjust the level of the item - log.Debugf("adding a new ordered list") - list := types.NewOrderedList(item) - // also, force the current item level to (last seen level + 1) - item.Level = maxLevel + 1 - // also, attach this list to the one above, if it exists ;) - // if len(lists) > 0 { - // parentList := &(lists[len(lists)-1]) - // parentItem := (*parentList).LastItem() - // parentItem.AddElement(list) - // return append(lists, list), nil - // } - return append(lists, list), nil -} - -func appendUnorderedListItem(lists []types.List, item *types.UnorderedListItem) ([]types.List, error) { - maxLevel := 0 - log.Debugf("looking-up list for unordered list item with level=%d and bullet style=%v", item.Level, item.BulletStyle) - for i, list := range lists { - if list, ok := list.(*types.UnorderedList); ok { - // assume we can't have empty lists - maxLevel++ - if list.Items[0].BulletStyle == item.BulletStyle { - log.Debugf("found a matching unordered list at level %d", list.Items[0].Level) - // prune items of "deeper/lower" level - lists = pruneLists(lists, i) - // apply the same level - item.Level = list.Items[0].Level - list.AddItem(*item) - return lists, nil - } - } - } - // no match found: create a new list and if needed, adjust the level of the item - log.Debugf("adding a new unordered list") - // also, force the current item level to (last seen level + 1) - item.Level = maxLevel + 1 - // also, force the bullet-style based on the list on the level above (if it exists) - if len(lists) > 0 { - parentList := &(lists[len(lists)-1]) - parentItem := (*parentList).LastItem() - // also, force the bullet style - if parentItem, ok := parentItem.(*types.UnorderedListItem); ok { - item.BulletStyle = item.BulletStyle.NextLevel(parentItem.BulletStyle) - } - } - list := types.NewUnorderedList(item) - return append(lists, list), nil -} - -func appendLabeledListItem(lists []types.List, item types.LabeledListItem) ([]types.List, error) { - maxLevel := 0 - log.Debugf("looking-up list for labeled list item with level=%d and term=%s", item.Level, item.Term) - for i, list := range lists { - log.Debugf(" comparing with list of type %T at level %d", list, i) - if list, ok := list.(*types.LabeledList); ok { - // assume we can't have empty lists - maxLevel++ - log.Debugf(" comparing with list item level %d vs %d", list.Items[0].Level, item.Level) - if list.Items[0].Level == item.Level { - log.Debugf("found a matching labeled list") - lists = pruneLists(lists, i) - list.AddItem(item) - log.Debugf("labeled list at level %d now has %d items", maxLevel, len(list.Items)) - return lists, nil - } - } - } - // no match found: create a new list and if needed, adjust the level of the item - log.Debugf("adding a new labeled list") - // also, force the current item level to (last seen level + 1) - item.Level = maxLevel + 1 - list := types.NewLabeledList(item) - return append(lists, list), nil -} - -func appendContinuedListItemElement(lists []types.List, item types.ContinuedListItemElement) []types.List { - lists = pruneLists(lists, len(lists)-1+item.Offset) - log.Debugf("appending continued list item element with offset=%d (depth=%d)", item.Offset, len(lists)) - // lookup the list at which the item should be attached - parentList := &(lists[len(lists)-1]) - parentItem := (*parentList).LastItem() - parentItem.AddElement(item.Element) - return lists -} - -func pruneLists(lists []types.List, level int) []types.List { - if level+1 < len(lists) { - log.Debugf("pruning the list path from %d to %d level(s) deep", len(lists), level+1) - // add the last list(s) as children of their parent, in reverse order, - // because we copy the value, not the pointers - for i := len(lists) - 1; i > level; i-- { - log.Debugf("appending list at depth %d to the last item of the parent list...", (i + 1)) - parentList := &(lists[i-1]) - parentItem := (*parentList).LastItem() - switch childList := lists[i].(type) { - case *types.OrderedList: - parentItem.AddElement(*childList) - case *types.UnorderedList: - parentItem.AddElement(*childList) - case *types.LabeledList: - parentItem.AddElement(*childList) - } - } - // also, prune the pointers to the remaining sublists - return lists[0 : level+1] - } - return lists -} - -// rearrangeSections moves elements into section to obtain a hierarchical document instead of a flat thing -func rearrangeSections(blocks []interface{}) (types.Document, error) { - - // use same logic as with list items: - // only append a child section to her parent section when - // a sibling or higher level section is processed. - - log.Debugf("rearranging sections in %d blocks...", len(blocks)) - tle := make([]interface{}, 0, len(blocks)) // top-level elements - sections := make([]types.Section, 0, 6) // the path to the current section (eg: []{section-level0, section-level1, etc.}) - elementRefs := types.ElementReferences{} - footnotes := types.Footnotes{} - footnoteRefs := types.FootnoteReferences{} - var previous *types.Section // the current "parent" section - for _, element := range blocks { - if e, ok := element.(types.Section); ok { - // avoid duplicate IDs in sections - referenceSection(e, elementRefs) - if previous == nil { // set first parent - log.Debugf("setting section with title %v as a top-level element", e.Title) - sections = append(sections, e) - } else if e.Level > previous.Level { // add new level - log.Debugf("adding section with title %v as the first section at level %d", e.Title, e.Level) - sections = append(sections, e) - } else { // replace at the deepest level - sections = pruneSections(sections, e.Level) - if len(sections) > 0 && sections[0].Level == e.Level { - log.Debugf("moving section with title %v as a new top-level element", e.Title) - tle = append(tle, sections[0]) - sections = make([]types.Section, 0, 6) - } - log.Debugf("adding section with title %v as another section at level %d", e.Title, e.Level) - sections = append(sections, e) - // if len(sections) == 1 { // we have new top-level element - // log.Debugf("setting section with title %v as secondary top-level", e.Title) - // tle = append(tle, &e) - // } else { - // log.Debugf("adding section with title %v as child of section at level %d", e.Title, (len(sections) - 2)) - // sections[len(sections)-2].AddElement(e) // attach to parent - // } - } - previous = &e // pointer to new current parent - } else { - if previous == nil { - // log.Debugf("adding element of type %T as a top-level element", element) - tle = append(tle, element) - } else { - parentSection := &(sections[len(sections)-1]) - // log.Debugf("adding element of type %T as a child of section with level %d", element, parentSection.Level) - (*parentSection).AddElement(element) - } - } - // also collect footnotes - if e, ok := element.(types.FootnotesContainer); ok { - // log.Debugf("collecting footnotes on element of type %T", element) - f, fr, err := e.Footnotes() - if err != nil { - return types.Document{}, errors.Wrap(err, "unable to collect footnotes in document") - } - footnotes = append(footnotes, f...) - for k, v := range fr { - footnoteRefs[k] = v - } - } - } - // process the remaining sections - sections = pruneSections(sections, 1) - if len(sections) > 0 { - tle = append(tle, sections[0]) - } - - return types.Document{ - Attributes: types.DocumentAttributes{}, - Elements: tle, - ElementReferences: elementRefs, - Footnotes: footnotes, - FootnoteReferences: footnoteRefs, - }, nil -} - -func referenceSection(e types.Section, elementRefs types.ElementReferences) { - id := e.Attributes.GetAsString(types.AttrID) - for i := 1; ; i++ { - var key string - if i == 1 { - key = id - } else { - key = id + "_" + strconv.Itoa(i) - } - if _, found := elementRefs[key]; !found { - elementRefs[key] = e.Title - // override the element id - e.Attributes[types.AttrID] = key - break - } - } - elementRefs[e.Attributes.GetAsString(types.AttrID)] = e.Title -} - -func pruneSections(sections []types.Section, level int) []types.Section { - if len(sections) > 0 && level > 0 { // && level < len(sections) { - log.Debugf("pruning the section path with %d level(s) of deep", len(sections)) - // add the last list(s) as children of their parent, in reverse order, - // because we copy the value, not the pointers - cut := len(sections) - for i := len(sections) - 1; i > 0 && sections[i].Level >= level; i-- { - parentSection := &(sections[i-1]) - log.Debugf("appending section at depth %d (%v) to the last element of the parent section (%v)", i, sections[i].Title, parentSection.Title) - (*parentSection).AddElement(sections[i]) - cut = i - } - // also, prune the pointers to the remaining sublists - sections := sections[0:cut] - log.Debugf("sections list has now %d top-level elements", len(sections)) - return sections - } - return sections -} diff --git a/pkg/parser/document_processing_apply_substitutions.go b/pkg/parser/document_processing_apply_substitutions.go new file mode 100644 index 00000000..7e760a45 --- /dev/null +++ b/pkg/parser/document_processing_apply_substitutions.go @@ -0,0 +1,131 @@ +package parser + +import ( + "strings" + + "github.com/bytesparadise/libasciidoc/pkg/types" + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" +) + +// applyDocumentAttributeSubstitutions(elements applies the document attribute substitutions +// and re-parse the paragraphs that were affected +func applyDocumentAttributeSubstitutions(element interface{}, attrs types.DocumentAttributes) (interface{}, error) { + // the document attributes, as they are resolved while processing the blocks + log.Debugf("applying document substitutions on block of type %T", element) + switch e := element.(type) { + case []interface{}: + elements := make([]interface{}, 0, len(e)) // maximum capacity cannot exceed initial input + for _, element := range e { + r, err := applyDocumentAttributeSubstitutions(element, attrs) + if err != nil { + return []interface{}{}, err + } + elements = append(elements, r) + } + // elements = filter(elements, DocumentAttributeMatcher) + return parseInlineLinks(types.MergeStringElements(elements)) + case types.DocumentAttributeDeclaration: + attrs[e.Name] = e.Value + return e, nil + case types.DocumentAttributeReset: + delete(attrs, e.Name) + return e, nil + case types.DocumentAttributeSubstitution: + if value, ok := attrs[e.Name].(string); ok { + return types.StringElement{ + Content: value, + }, nil + } + return types.StringElement{ + Content: "{" + e.Name + "}", + }, nil + case types.ImageBlock: + return e.ResolveLocation(attrs), nil + case types.InlineImage: + return e.ResolveLocation(attrs), nil + case types.Section: + title, err := applyDocumentAttributeSubstitutions(e.Title, attrs) + if err != nil { + return struct{}{}, err + } + if title, ok := title.([]interface{}); ok { + e.Title = title + } + return e.ResolveID(attrs) + case types.OrderedListItem: + elements, err := applyDocumentAttributeSubstitutions(e.Elements, attrs) + if err != nil { + return struct{}{}, err + } + e.Elements = elements.([]interface{}) + return e, nil + case types.UnorderedListItem: + elements, err := applyDocumentAttributeSubstitutions(e.Elements, attrs) + if err != nil { + return struct{}{}, err + } + e.Elements = elements.([]interface{}) + return e, nil + case types.LabeledListItem: + elements, err := applyDocumentAttributeSubstitutions(e.Elements, attrs) + if err != nil { + return struct{}{}, err + } + e.Elements = elements.([]interface{}) + return e, nil + case types.QuotedText: + elements, err := applyDocumentAttributeSubstitutions(e.Elements, attrs) + if err != nil { + return struct{}{}, err + } + e.Elements = elements.([]interface{}) + return e, nil + case types.ContinuedListItemElement: + element, err := applyDocumentAttributeSubstitutions(e.Element, attrs) + if err != nil { + return struct{}{}, err + } + e.Element = element + return e, nil + case types.DelimitedBlock: + elements, err := applyDocumentAttributeSubstitutions(e.Elements, attrs) + if err != nil { + return struct{}{}, err + } + e.Elements = elements.([]interface{}) + return e, nil + case types.Paragraph: + for i, line := range e.Lines { + line, err := applyDocumentAttributeSubstitutions(line, attrs) + if err != nil { + return struct{}{}, err + } + e.Lines[i] = line.([]interface{}) + } + return e, nil + default: + return e, nil + } +} + +// if a document attribute substitution happened, we need to parse the string element in search +// for a potentially new link. Eg `{url}` giving `https://foo.com` +func parseInlineLinks(elements []interface{}) ([]interface{}, error) { + result := []interface{}{} + for _, element := range elements { + switch element := element.(type) { + case types.StringElement: + log.Debugf("looking for links in line element of type %[1]T (%[1]v)", element) + elements, err := ParseReader("", strings.NewReader(element.Content), Entrypoint("InlineLinks")) + if err != nil { + return []interface{}{}, errors.Wrap(err, "error while parsing content for inline links") + } + log.Debugf(" found: %+v", elements) + result = append(result, elements.([]interface{})...) + default: + result = append(result, element) + } + } + return result, nil +} diff --git a/pkg/parser/document_processing_apply_substitutions_test.go b/pkg/parser/document_processing_apply_substitutions_test.go new file mode 100644 index 00000000..835766b9 --- /dev/null +++ b/pkg/parser/document_processing_apply_substitutions_test.go @@ -0,0 +1,543 @@ +package parser + +import ( + "github.com/bytesparadise/libasciidoc/pkg/types" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("document attribute subsititutions", func() { + + It("should replace with new StringElement on first position", func() { + // given + elements := []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.DocumentAttributeSubstitution{ + Name: "foo", + }, + types.StringElement{ + Content: " and more content.", + }, + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{ + "foo": "bar", + }) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "bar and more content.", + }, + }, + }, + }, + })) + }) + + It("should replace with new StringElement on first position", func() { + // given + elements := []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.DocumentAttributeSubstitution{ + Name: "foo", + }, + types.StringElement{ + Content: " and more content.", + }, + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{ + "foo": "bar", + }) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "bar and more content.", + }, + }, + }, + }, + })) + }) + + It("should replace with new StringElement on middle position", func() { + // given + elements := []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "baz, ", + }, + types.DocumentAttributeSubstitution{ + Name: "foo", + }, + types.StringElement{ + Content: " and more content.", + }, + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{ + "foo": "bar", + }) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "baz, bar and more content.", + }, + }, + }, + }, + })) + }) + + It("should replace with undefined attribute", func() { + // given + elements := []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "baz, ", + }, + types.DocumentAttributeSubstitution{ + Name: "foo", + }, + types.StringElement{ + Content: " and more content.", + }, + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{}) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "baz, {foo} and more content.", + }, + }, + }, + }, + })) + }) + + It("should merge without substitution", func() { + // given + elements := []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "baz, ", + }, + types.StringElement{ + Content: "foo", + }, + types.StringElement{ + Content: " and more content.", + }, + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{}) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "baz, foo and more content.", + }, + }, + }, + }, + })) + }) + + It("should replace with new link", func() { + // given + elements := []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "a link to ", + }, + types.DocumentAttributeSubstitution{ + Name: "scheme", + }, + types.StringElement{ + Content: "://", + }, + types.DocumentAttributeSubstitution{ + Name: "host", + }, + types.StringElement{ + Content: "[].", // explicit use of `[]` to avoid grabbing the `.` + }, + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{ + "scheme": "https", + "host": "foo.bar", + }) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "a link to ", + }, + types.InlineLink{ + Attributes: types.ElementAttributes{}, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "https://foo.bar", + }, + }, + }, + }, + types.StringElement{ + Content: ".", + }, + }, + }, + }, + })) + }) + + Context("list items", func() { + + It("should replace with new StringElement in ordered list item", func() { + // given + elements := []interface{}{ + types.OrderedListItem{ + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.DocumentAttributeSubstitution{ + Name: "foo", + }, + types.StringElement{ + Content: " and more content.", + }, + }, + }, + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{ + "foo": "bar", + }) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.OrderedListItem{ + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "bar and more content.", + }, + }, + }, + }, + }, + }, + })) + }) + + It("should replace with new StringElement in unordered list item", func() { + // given + elements := []interface{}{ + types.UnorderedListItem{ + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.DocumentAttributeSubstitution{ + Name: "foo", + }, + types.StringElement{ + Content: " and more content.", + }, + }, + }, + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{ + "foo": "bar", + }) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.UnorderedListItem{ + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "bar and more content.", + }, + }, + }, + }, + }, + }, + })) + }) + + It("should replace with new StringElement in labeled list item", func() { + // given + elements := []interface{}{ + types.LabeledListItem{ + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.DocumentAttributeSubstitution{ + Name: "foo", + }, + types.StringElement{ + Content: " and more content.", + }, + }, + }, + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{ + "foo": "bar", + }) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.LabeledListItem{ + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "bar and more content.", + }, + }, + }, + }, + }, + }, + })) + }) + }) + + Context("delimited blocks", func() { + + It("should replace with new StringElement in delimited block", func() { + // given + elements := []interface{}{ + types.DelimitedBlock{ + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.DocumentAttributeSubstitution{ + Name: "foo", + }, + types.StringElement{ + Content: " and more content.", + }, + }, + }, + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{ + "foo": "bar", + }) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.DelimitedBlock{ + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "bar and more content.", + }, + }, + }, + }, + }, + }, + })) + }) + }) + + Context("quoted text", func() { + + It("should replace with new StringElement in quoted text", func() { + // given + elements := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "hello ", + }, + types.QuotedText{ + Elements: []interface{}{ + types.DocumentAttributeSubstitution{ + Name: "foo", + }, + types.StringElement{ + Content: " and more content.", + }, + }, + }, + }, + { + types.StringElement{ + Content: "and another line", + }, + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{ + "foo": "bar", + }) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{ + Content: "hello ", + }, + types.QuotedText{ + Elements: []interface{}{ + types.StringElement{ + Content: "bar and more content.", + }, + }, + }, + }, + { + types.StringElement{ + Content: "and another line", + }, + }, + }, + }, + })) + }) + }) + + Context("tables", func() { + + It("should replace with new StringElement in table cell", func() { + // given + elements := []interface{}{ + types.DelimitedBlock{ + Elements: []interface{}{ + types.DocumentAttributeSubstitution{ + Name: "foo", + }, + types.StringElement{ + Content: " and more content.", + }, + }, + }, + } + // when + result, err := applyDocumentAttributeSubstitutions(elements, types.DocumentAttributes{ + "foo": "bar", + }) + // then + Expect(err).To(Not(HaveOccurred())) + Expect(result).To(Equal([]interface{}{ + types.DelimitedBlock{ + Elements: []interface{}{ + types.StringElement{ + Content: "bar and more content.", + }, + }, + }, + })) + }) + }) +}) diff --git a/pkg/parser/document_processing_filter_blocks.go b/pkg/parser/document_processing_filter_blocks.go new file mode 100644 index 00000000..1f955775 --- /dev/null +++ b/pkg/parser/document_processing_filter_blocks.go @@ -0,0 +1,123 @@ +package parser + +import ( + "github.com/bytesparadise/libasciidoc/pkg/types" + log "github.com/sirupsen/logrus" +) + +// Filter removes all blocks that should not appear in the final document: +// - blank lines (except in delimited blocks) +// - all document attribute declaration/substitution/reset +// - empty preambles +// - single line comments and comment blocks +func filter(elements []interface{}, matchers ...filterMatcher) []interface{} { + result := make([]interface{}, 0, len(elements)) +elements: + for _, element := range elements { + // check if filter option applies to the element + for _, match := range matchers { + if match(element) { + log.Debugf("discarding element of type '%T'", element) + continue elements + } + } + log.Debugf("keeping element of type '%T'", element) + + // also, process the content if the element to retain + switch e := element.(type) { + case types.Preamble: + e.Elements = filter(e.Elements, matchers...) + result = append(result, e) + case types.Paragraph: + lines := make([][]interface{}, 0, len(e.Lines)) + for _, l := range e.Lines { + l = filter(l, matchers...) + if len(l) > 0 { + lines = append(lines, l) + } + } + e.Lines = lines + result = append(result, e) + case types.OrderedList: + items := make([]types.OrderedListItem, 0, len(e.Items)) + for _, i := range e.Items { + i.Elements = filter(i.Elements, matchers...) + items = append(items, i) + } + e.Items = items + result = append(result, e) + case types.UnorderedList: + items := make([]types.UnorderedListItem, 0, len(e.Items)) + for _, i := range e.Items { + i.Elements = filter(i.Elements, matchers...) + items = append(items, i) + } + e.Items = items + result = append(result, e) + case types.LabeledList: + items := make([]types.LabeledListItem, 0, len(e.Items)) + for _, i := range e.Items { + i.Elements = filter(i.Elements, matchers...) + items = append(items, i) + } + e.Items = items + result = append(result, e) + default: + result = append(result, e) + } + } + return result +} + +// AllMatchers all the matchers needed to remove the unneeded blocks/elements from the final document +var allMatchers = []filterMatcher{blankLineMatcher, emptyPreambleMatcher, documentAttributeMatcher, singleLineCommentMatcher, commentBlockMatcher} + +// filterMatcher returns true if the given element is to be filtered out +type filterMatcher func(element interface{}) bool + +// emptyPreambleMatcher filters the element if it is an empty preamble +var emptyPreambleMatcher filterMatcher = func(element interface{}) bool { + result := false + if p, match := element.(types.Preamble); match { + result = p.Elements == nil || len(p.Elements) == 0 + } + // log.Debugf(" element of type '%T' is an empty preamble: %t", element, result) + return result +} + +// blankLineMatcher filters the element if it is a blank line +var blankLineMatcher filterMatcher = func(element interface{}) bool { + _, result := element.(types.BlankLine) + return result +} + +// documentAttributeMatcher filters the element if it is a DocumentAttributeDeclaration, +// a DocumentAttributeSubstitution or a DocumentAttributeReset +var documentAttributeMatcher filterMatcher = func(element interface{}) bool { + switch element.(type) { + case types.DocumentAttributeDeclaration, types.DocumentAttributeSubstitution, types.DocumentAttributeReset: + return true + default: + return false + } +} + +// singleLineCommentMatcher filters the element if it is a SingleLineComment +var singleLineCommentMatcher filterMatcher = func(element interface{}) bool { + switch element.(type) { + case types.SingleLineComment: + return true + default: + return false + } +} + +// commentBlockMatcher filters the element if it is a DelimitedBlock of kind 'Comment' +var commentBlockMatcher filterMatcher = func(element interface{}) bool { + switch e := element.(type) { + case types.DelimitedBlock: + return e.Kind == types.Comment + default: + return false + } +} diff --git a/pkg/parser/document_processing_filter_blocks_test.go b/pkg/parser/document_processing_filter_blocks_test.go new file mode 100644 index 00000000..017ed03d --- /dev/null +++ b/pkg/parser/document_processing_filter_blocks_test.go @@ -0,0 +1,322 @@ +package parser + +import ( + "github.com/bytesparadise/libasciidoc/pkg/types" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("block filters", func() { + + It("should remove blank line", func() { + actual := []interface{}{ + types.BlankLine{}, + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + expected := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should retain blank line in a delimited block", func() { + actual := []interface{}{ + types.DelimitedBlock{ + Kind: types.Fenced, + Elements: []interface{}{ + types.BlankLine{}, + }, + }, + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + expected := []interface{}{ + types.DelimitedBlock{ + Kind: types.Fenced, + Elements: []interface{}{ + types.BlankLine{}, + }, + }, + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should remove document attribute declaration", func() { + actual := []interface{}{ + types.DocumentAttributeDeclaration{}, + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + expected := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should remove document attribute substitution", func() { + actual := []interface{}{ + types.DocumentAttributeSubstitution{}, + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + expected := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should remove document attribute reset", func() { + actual := []interface{}{ + types.DocumentAttributeReset{}, + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + expected := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should remove comment block", func() { + actual := []interface{}{ + types.DelimitedBlock{ + Kind: types.Comment, + }, + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + expected := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should remove single line comment as a block", func() { + actual := []interface{}{ + types.SingleLineComment{}, + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + expected := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should remove single line comment in a paragraph", func() { + actual := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + types.SingleLineComment{}, + }, + }, + }, + } + expected := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.StringElement{}, + }, + }, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should retain paragraph with single line comment only", func() { + actual := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{ + { + types.SingleLineComment{}, + }, + }, + }, + } + expected := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{}, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should retain paragraph with empty content", func() { + actual := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{}, + }, + } + expected := []interface{}{ + types.Paragraph{ + Lines: [][]interface{}{}, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should remove single line comment in an ordered list item", func() { + actual := []interface{}{ + types.OrderedList{ + Items: []types.OrderedListItem{ + { + Elements: []interface{}{ + types.StringElement{}, + types.SingleLineComment{}, + }, + }, + }, + }, + } + expected := []interface{}{ + types.OrderedList{ + Items: []types.OrderedListItem{ + { + Elements: []interface{}{ + types.StringElement{}, + }, + }, + }, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should remove single line comment in an ordered list item", func() { + actual := []interface{}{ + types.UnorderedList{ + Items: []types.UnorderedListItem{ + { + Elements: []interface{}{ + types.StringElement{}, + types.SingleLineComment{}, + }, + }, + }, + }, + } + expected := []interface{}{ + types.UnorderedList{ + Items: []types.UnorderedListItem{ + { + Elements: []interface{}{ + types.StringElement{}, + }, + }, + }, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + + It("should remove single line comment in an labeled list item", func() { + actual := []interface{}{ + types.LabeledList{ + Items: []types.LabeledListItem{ + { + Elements: []interface{}{ + types.StringElement{}, + types.SingleLineComment{}, + }, + }, + }, + }, + } + expected := []interface{}{ + types.LabeledList{ + Items: []types.LabeledListItem{ + { + Elements: []interface{}{ + types.StringElement{}, + }, + }, + }, + }, + } + Expect(filter(actual, allMatchers...)).To(Equal(expected)) + }) + +}) diff --git a/pkg/parser/document_processing_rearrange_lists.go b/pkg/parser/document_processing_rearrange_lists.go new file mode 100644 index 00000000..9f2aed55 --- /dev/null +++ b/pkg/parser/document_processing_rearrange_lists.go @@ -0,0 +1,245 @@ +package parser + +import ( + "reflect" + + "github.com/bytesparadise/libasciidoc/pkg/types" + + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" +) + +// rearrangeListItems moves the list items into lists, and nested lists if needed +func rearrangeListItems(blocks []interface{}, withinDelimitedBlock bool) ([]interface{}, error) { + // log.Debugf("rearranging list items in %d blocks...", len(blocks)) + result := make([]interface{}, 0, len(blocks)) // maximum capacity cannot exceed initial input + lists := []types.List{} // at each level (or depth), we have a list, whatever its type. + blankline := false // track if the previous block was a blank line + for _, block := range blocks { + switch block := block.(type) { + case types.DelimitedBlock: + // process and replace the elements within this delimited block + elements, err := rearrangeListItems(block.Elements, true) + if err != nil { + return nil, errors.Wrapf(err, "unable to rearrange list items in delimited block") + } + block.Elements = elements + if len(lists) > 0 { + switch list := lists[0].(type) { // just add the top-level list + case *types.OrderedList: + result = append(result, *list) + case *types.UnorderedList: + result = append(result, *list) + case *types.LabeledList: + result = append(result, *list) + } + // reset the list for further usage while processing the rest of the document + lists = []types.List{} + } + result = append(result, block) + case types.OrderedListItem, types.UnorderedListItem, types.LabeledListItem: + // there's a special case: if the next list item has attributes and was preceded by a + // blank line, then we need to start a new list + if blankline && len(block.(types.DocumentElement).GetAttributes()) > 0 { + if len(lists) > 0 { + for _, list := range pruneLists(lists, 0) { + result = append(result, unPtr(list)) + } + // reset the list for further usage while processing the rest of the document + lists = []types.List{} + } + } + var err error + lists, err = appendListItem(lists, block) + if err != nil { + return nil, errors.Wrapf(err, "unable to rearrange list items in delimited block") + } + blankline = false + case types.ContinuedListItemElement: + lists = appendContinuedListItemElement(lists, block) + blankline = false + case types.BlankLine: + // blank lines are not part of the resulting Document sections (or top-level), but they are part of the delimited blocks + // in some cases, they can also be used to split lists apart (when the next item has some attributes, + // or if the next block is a comment) + if withinDelimitedBlock && len(lists) == 0 { // only retain blank lines if within a delimited block, but not currently dealing with a list (or a set of nested lists) + result = append(result, block) + } + blankline = true + default: + blankline = false + // an block which is not a list item was found. + // the first thing to do is to process the pending list items, + // then only append this block to the result + if len(lists) > 0 { + log.Debugf("appending %d lists before processing element of type %T", len(lists), block) + for _, list := range pruneLists(lists, 0) { + result = append(result, unPtr(list)) + } + // reset the list for further usage while processing the rest of the document + lists = []types.List{} + } + result = append(result, block) + } + } + // also when all is done, process the remaining pending list items + if len(lists) > 0 { + log.Debugf("processing the remaining %d lists...", len(lists)) + for _, list := range pruneLists(lists, 0) { + result = append(result, unPtr(list)) + } + } + return result, nil +} + +func unPtr(value interface{}) interface{} { + v := reflect.ValueOf(value) + k := v.Kind() + if k == reflect.Ptr && v.Elem().IsValid() { + return v.Elem().Interface() + } + return value +} + +func appendListItem(lists []types.List, item interface{}) ([]types.List, error) { + switch item := item.(type) { + case types.OrderedListItem: + return appendOrderedListItem(lists, &item) + case types.UnorderedListItem: + return appendUnorderedListItem(lists, &item) + case types.LabeledListItem: + return appendLabeledListItem(lists, item) + } + return lists, nil +} + +func appendOrderedListItem(lists []types.List, item *types.OrderedListItem) ([]types.List, error) { + maxLevel := 0 + log.Debugf("looking-up list for ordered list having items with level=%d and number style=%v", item.Level, item.NumberingStyle) + for i, list := range lists { + if list, ok := list.(*types.OrderedList); ok { + // assume we can't have empty lists + maxLevel++ + if list.Items[0].NumberingStyle == item.NumberingStyle { + log.Debugf("found a matching ordered list at level %d", list.Items[0].Level) + // prune items of "deeper/lower" level + lists = pruneLists(lists, i) + // apply the same level + item.Level = list.Items[0].Level + list.AddItem(*item) + // also, prune the pointers to the remaining sublists (in case there is any...) + return lists, nil + } + } + } + // force the current item level to (last seen level + 1) + item.Level = maxLevel + 1 + // no match found: create a new list and if needed, adjust the level of the item + log.Debugf("adding a new ordered list") + list := types.NewOrderedList(item) + // also, force the current item level to (last seen level + 1) + item.Level = maxLevel + 1 + // also, attach this list to the one above, if it exists ;) + // if len(lists) > 0 { + // parentList := &(lists[len(lists)-1]) + // parentItem := (*parentList).LastItem() + // parentItem.AddElement(list) + // return append(lists, list), nil + // } + return append(lists, list), nil +} + +func appendUnorderedListItem(lists []types.List, item *types.UnorderedListItem) ([]types.List, error) { + maxLevel := 0 + log.Debugf("looking-up list for unordered list item with level=%d and bullet style=%v", item.Level, item.BulletStyle) + for i, list := range lists { + if list, ok := list.(*types.UnorderedList); ok { + // assume we can't have empty lists + maxLevel++ + if list.Items[0].BulletStyle == item.BulletStyle { + log.Debugf("found a matching unordered list at level %d", list.Items[0].Level) + // prune items of "deeper/lower" level + lists = pruneLists(lists, i) + // apply the same level + item.Level = list.Items[0].Level + list.AddItem(*item) + return lists, nil + } + } + } + // no match found: create a new list and if needed, adjust the level of the item + log.Debugf("adding a new unordered list") + // also, force the current item level to (last seen level + 1) + item.Level = maxLevel + 1 + // also, force the bullet-style based on the list on the level above (if it exists) + if len(lists) > 0 { + parentList := &(lists[len(lists)-1]) + parentItem := (*parentList).LastItem() + // also, force the bullet style + if parentItem, ok := parentItem.(*types.UnorderedListItem); ok { + item.BulletStyle = item.BulletStyle.NextLevel(parentItem.BulletStyle) + } + } + list := types.NewUnorderedList(item) + return append(lists, list), nil +} + +func appendLabeledListItem(lists []types.List, item types.LabeledListItem) ([]types.List, error) { + maxLevel := 0 + log.Debugf("looking-up list for labeled list item with level=%d and term=%s", item.Level, item.Term) + for i, list := range lists { + log.Debugf(" comparing with list of type %T at level %d", list, i) + if list, ok := list.(*types.LabeledList); ok { + // assume we can't have empty lists + maxLevel++ + log.Debugf(" comparing with list item level %d vs %d", list.Items[0].Level, item.Level) + if list.Items[0].Level == item.Level { + log.Debugf("found a matching labeled list") + lists = pruneLists(lists, i) + list.AddItem(item) + log.Debugf("labeled list at level %d now has %d items", maxLevel, len(list.Items)) + return lists, nil + } + } + } + // no match found: create a new list and if needed, adjust the level of the item + log.Debugf("adding a new labeled list") + // also, force the current item level to (last seen level + 1) + item.Level = maxLevel + 1 + list := types.NewLabeledList(item) + return append(lists, list), nil +} + +func appendContinuedListItemElement(lists []types.List, item types.ContinuedListItemElement) []types.List { + lists = pruneLists(lists, len(lists)-1+item.Offset) + log.Debugf("appending continued list item element with offset=%d (depth=%d)", item.Offset, len(lists)) + // lookup the list at which the item should be attached + parentList := &(lists[len(lists)-1]) + parentItem := (*parentList).LastItem() + parentItem.AddElement(item.Element) + return lists +} + +func pruneLists(lists []types.List, level int) []types.List { + if level+1 < len(lists) { + log.Debugf("pruning the list path from %d to %d level(s) deep", len(lists), level+1) + // add the last list(s) as children of their parent, in reverse order, + // because we copy the value, not the pointers + for i := len(lists) - 1; i > level; i-- { + log.Debugf("appending list at depth %d to the last item of the parent list...", (i + 1)) + parentList := &(lists[i-1]) + parentItem := (*parentList).LastItem() + switch childList := lists[i].(type) { + case *types.OrderedList: + parentItem.AddElement(*childList) + case *types.UnorderedList: + parentItem.AddElement(*childList) + case *types.LabeledList: + parentItem.AddElement(*childList) + } + } + // also, prune the pointers to the remaining sublists + return lists[0 : level+1] + } + return lists +} diff --git a/pkg/parser/document_processing_rearrange_lists_test.go b/pkg/parser/document_processing_rearrange_lists_test.go new file mode 100644 index 00000000..b1f674fd --- /dev/null +++ b/pkg/parser/document_processing_rearrange_lists_test.go @@ -0,0 +1,423 @@ +package parser + +import ( + "github.com/bytesparadise/libasciidoc/pkg/types" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("rearrange lists", func() { + + It("mixed lists - complex case 1", func() { + // - unordered 1 + // 1. ordered 1.1 + // a. ordered 1.1.a + // b. ordered 1.1.b + // c. ordered 1.1.c + // 2. ordered 1.2 + // i) ordered 1.2.i + // ii) ordered 1.2.ii + // 3. ordered 1.3 + // 4. ordered 1.4 + // - unordered 2 + // * unordered 2.1 + actual := []interface{}{ + types.UnorderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 1, + BulletStyle: types.Dash, + CheckStyle: types.NoCheck, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "unordered 1"}, + }, + }, + }, + }, + }, + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.1"}, + }, + }, + }, + }, + }, + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 2, + NumberingStyle: types.LowerAlpha, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.1.a"}, + }, + }, + }, + }, + }, + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 2, + NumberingStyle: types.LowerAlpha, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.1.b"}, + }, + }, + }, + }, + }, + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 2, + NumberingStyle: types.LowerAlpha, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.1.c"}, + }, + }, + }, + }, + }, + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.2"}, + }, + }, + }, + }, + }, + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 2, + NumberingStyle: types.LowerRoman, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.2.i"}, + }, + }, + }, + }, + }, + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 2, + NumberingStyle: types.LowerRoman, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.2.ii"}, + }, + }, + }, + }, + }, + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.3"}, + }, + }, + }, + }, + }, + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.4"}, + }, + }, + }, + }, + }, + types.UnorderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 1, + BulletStyle: types.Dash, + CheckStyle: types.NoCheck, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "unordered 2"}, + }, + }, + }, + }, + }, + types.UnorderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 2, + BulletStyle: types.OneAsterisk, + CheckStyle: types.NoCheck, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "unordered 2.1"}, + }, + }, + }, + }, + }, + } + expected := []interface{}{ + types.UnorderedList{ + Attributes: types.ElementAttributes{}, + Items: []types.UnorderedListItem{ + { + Attributes: types.ElementAttributes{}, + Level: 1, + BulletStyle: types.Dash, + CheckStyle: types.NoCheck, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "unordered 1"}, + }, + }, + }, + types.OrderedList{ + Attributes: types.ElementAttributes{}, + Items: []types.OrderedListItem{ + { + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.1"}, + }, + }, + }, + types.OrderedList{ + Attributes: types.ElementAttributes{}, + Items: []types.OrderedListItem{ + { + Attributes: types.ElementAttributes{}, + Level: 2, + NumberingStyle: types.LowerAlpha, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.1.a"}, + }, + }, + }, + }, + }, + { + Attributes: types.ElementAttributes{}, + Level: 2, + NumberingStyle: types.LowerAlpha, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.1.b"}, + }, + }, + }, + }, + }, + { + Attributes: types.ElementAttributes{}, + Level: 2, + NumberingStyle: types.LowerAlpha, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.1.c"}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.2"}, + }, + }, + }, + types.OrderedList{ + Attributes: types.ElementAttributes{}, + Items: []types.OrderedListItem{ + { + Attributes: types.ElementAttributes{}, + Level: 2, + NumberingStyle: types.LowerRoman, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.2.i"}, + }, + }, + }, + }, + }, + { + Attributes: types.ElementAttributes{}, + Level: 2, + NumberingStyle: types.LowerRoman, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.2.ii"}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.3"}, + }, + }, + }, + }, + }, + { + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "ordered 1.4"}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + Attributes: types.ElementAttributes{}, + Level: 1, + BulletStyle: types.Dash, + CheckStyle: types.NoCheck, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "unordered 2"}, + }, + }, + }, + types.UnorderedList{ + Attributes: types.ElementAttributes{}, + Items: []types.UnorderedListItem{ + { + Attributes: types.ElementAttributes{}, + Level: 2, + BulletStyle: types.OneAsterisk, + CheckStyle: types.NoCheck, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "unordered 2.1"}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + result, err := rearrangeListItems(actual, false) + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(expected)) + }) +}) diff --git a/pkg/parser/document_processing_rearrange_sections.go b/pkg/parser/document_processing_rearrange_sections.go new file mode 100644 index 00000000..129e7f17 --- /dev/null +++ b/pkg/parser/document_processing_rearrange_sections.go @@ -0,0 +1,128 @@ +package parser + +import ( + "strconv" + + "github.com/bytesparadise/libasciidoc/pkg/types" + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" +) + +// rearrangeSections moves elements into section to obtain a hierarchical document instead of a flat thing +func rearrangeSections(blocks []interface{}) (types.Document, error) { + + // use same logic as with list items: + // only append a child section to her parent section when + // a sibling or higher level section is processed. + + log.Debugf("rearranging sections in %d blocks...", len(blocks)) + tle := make([]interface{}, 0, len(blocks)) // top-level elements + sections := make([]types.Section, 0, 6) // the path to the current section (eg: []{section-level0, section-level1, etc.}) + elementRefs := types.ElementReferences{} + footnotes := types.Footnotes{} + footnoteRefs := types.FootnoteReferences{} + var previous *types.Section // the current "parent" section + for _, element := range blocks { + if e, ok := element.(types.Section); ok { + // avoid duplicate IDs in sections + referenceSection(e, elementRefs) + if previous == nil { // set first parent + log.Debugf("setting section with title %v as a top-level element", e.Title) + sections = append(sections, e) + } else if e.Level > previous.Level { // add new level + log.Debugf("adding section with title %v as the first section at level %d", e.Title, e.Level) + sections = append(sections, e) + } else { // replace at the deepest level + sections = pruneSections(sections, e.Level) + if len(sections) > 0 && sections[0].Level == e.Level { + log.Debugf("moving section with title %v as a new top-level element", e.Title) + tle = append(tle, sections[0]) + sections = make([]types.Section, 0, 6) + } + log.Debugf("adding section with title %v as another section at level %d", e.Title, e.Level) + sections = append(sections, e) + // if len(sections) == 1 { // we have new top-level element + // log.Debugf("setting section with title %v as secondary top-level", e.Title) + // tle = append(tle, &e) + // } else { + // log.Debugf("adding section with title %v as child of section at level %d", e.Title, (len(sections) - 2)) + // sections[len(sections)-2].AddElement(e) // attach to parent + // } + } + previous = &e // pointer to new current parent + } else { + if previous == nil { + // log.Debugf("adding element of type %T as a top-level element", element) + tle = append(tle, element) + } else { + parentSection := &(sections[len(sections)-1]) + // log.Debugf("adding element of type %T as a child of section with level %d", element, parentSection.Level) + (*parentSection).AddElement(element) + } + } + // also collect footnotes + if e, ok := element.(types.FootnotesContainer); ok { + // log.Debugf("collecting footnotes on element of type %T", element) + f, fr, err := e.Footnotes() + if err != nil { + return types.Document{}, errors.Wrap(err, "unable to collect footnotes in document") + } + footnotes = append(footnotes, f...) + for k, v := range fr { + footnoteRefs[k] = v + } + } + } + // process the remaining sections + sections = pruneSections(sections, 1) + if len(sections) > 0 { + tle = append(tle, sections[0]) + } + + return types.Document{ + Attributes: types.DocumentAttributes{}, + Elements: tle, + ElementReferences: elementRefs, + Footnotes: footnotes, + FootnoteReferences: footnoteRefs, + }, nil +} + +func referenceSection(e types.Section, elementRefs types.ElementReferences) { + id := e.Attributes.GetAsString(types.AttrID) + for i := 1; ; i++ { + var key string + if i == 1 { + key = id + } else { + key = id + "_" + strconv.Itoa(i) + } + if _, found := elementRefs[key]; !found { + elementRefs[key] = e.Title + // override the element id + e.Attributes[types.AttrID] = key + break + } + } + elementRefs[e.Attributes.GetAsString(types.AttrID)] = e.Title +} + +func pruneSections(sections []types.Section, level int) []types.Section { + if len(sections) > 0 && level > 0 { // && level < len(sections) { + log.Debugf("pruning the section path with %d level(s) of deep", len(sections)) + // add the last list(s) as children of their parent, in reverse order, + // because we copy the value, not the pointers + cut := len(sections) + for i := len(sections) - 1; i > 0 && sections[i].Level >= level; i-- { + parentSection := &(sections[i-1]) + log.Debugf("appending section at depth %d (%v) to the last element of the parent section (%v)", i, sections[i].Title, parentSection.Title) + (*parentSection).AddElement(sections[i]) + cut = i + } + // also, prune the pointers to the remaining sublists + sections := sections[0:cut] + log.Debugf("sections list has now %d top-level elements", len(sections)) + return sections + } + return sections +} diff --git a/pkg/parser/document_processing_rearrange_sections_test.go b/pkg/parser/document_processing_rearrange_sections_test.go new file mode 100644 index 00000000..8db51711 --- /dev/null +++ b/pkg/parser/document_processing_rearrange_sections_test.go @@ -0,0 +1,497 @@ +package parser + +import ( + "github.com/bytesparadise/libasciidoc/pkg/types" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("rearrange sections", func() { + + It("section levels 1, 2, 3, 2", func() { + // = a header + // + // == Section A + // a paragraph + // + // === Section A.a + // a paragraph + // + // == Section B + // a paragraph + doctitle := []interface{}{ + types.StringElement{Content: "a header"}, + } + sectionATitle := []interface{}{ + types.StringElement{Content: "Section A"}, + } + sectionAaTitle := []interface{}{ + types.StringElement{Content: "Section A.a"}, + } + sectionBTitle := []interface{}{ + types.StringElement{Content: "Section B"}, + } + actual := []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_a_header", + }, + Level: 0, + Title: doctitle, + Elements: []interface{}{}, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a", + }, + Level: 1, + Title: sectionATitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a_a", + }, + Level: 2, + Title: sectionAaTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_b", + }, + Level: 1, + Title: sectionBTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + } + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{ + "_a_header": doctitle, + "_section_a": sectionATitle, + "_section_a_a": sectionAaTitle, + "_section_b": sectionBTitle, + }, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_a_header", + }, + Level: 0, + Title: doctitle, + Elements: []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a", + }, + Level: 1, + Title: sectionATitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a_a", + }, + Level: 2, + Title: sectionAaTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_b", + }, + Level: 1, + Title: sectionBTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + result, err := rearrangeSections(actual) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(expected)) + }) + + It("section levels 1, 2, 3, 3", func() { + // = a header + // + // == Section A + // a paragraph + // + // === Section A.a + // a paragraph + // + // === Section A.b + // a paragraph + doctitle := []interface{}{ + types.StringElement{Content: "a header"}, + } + sectionATitle := []interface{}{ + types.StringElement{Content: "Section A"}, + } + sectionAaTitle := []interface{}{ + types.StringElement{Content: "Section A.a"}, + } + sectionBTitle := []interface{}{ + types.StringElement{Content: "Section A.b"}, + } + actual := []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_a_header", + }, + Level: 0, + Title: doctitle, + Elements: []interface{}{}, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a", + }, + Level: 1, + Title: sectionATitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a_a", + }, + Level: 2, + Title: sectionAaTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a_b", + }, + Level: 2, + Title: sectionBTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + } + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{ + "_a_header": doctitle, + "_section_a": sectionATitle, + "_section_a_a": sectionAaTitle, + "_section_a_b": sectionBTitle, + }, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_a_header", + }, + Level: 0, + Title: doctitle, + Elements: []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a", + }, + Level: 1, + Title: sectionATitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a_a", + }, + Level: 2, + Title: sectionAaTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a_b", + }, + Level: 2, + Title: sectionBTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + result, err := rearrangeSections(actual) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(expected)) + }) + + It("section levels 1, 3, 4, 4", func() { + // = a header + // + // === Section A + // a paragraph + // + // ==== Section A.a + // a paragraph + // + // ==== Section A.b + // a paragraph + doctitle := []interface{}{ + types.StringElement{Content: "a header"}, + } + sectionATitle := []interface{}{ + types.StringElement{Content: "Section A"}, + } + sectionAaTitle := []interface{}{ + types.StringElement{Content: "Section A.a"}, + } + sectionBTitle := []interface{}{ + types.StringElement{Content: "Section A.b"}, + } + actual := []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_a_header", + }, + Level: 0, + Title: doctitle, + Elements: []interface{}{}, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a", + }, + Level: 2, + Title: sectionATitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a_a", + }, + Level: 3, + Title: sectionAaTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a_b", + }, + Level: 3, + Title: sectionBTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + } + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{ + "_a_header": doctitle, + "_section_a": sectionATitle, + "_section_a_a": sectionAaTitle, + "_section_a_b": sectionBTitle, + }, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_a_header", + }, + Level: 0, + Title: doctitle, + Elements: []interface{}{ + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a", + }, + Level: 2, + Title: sectionATitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a_a", + }, + Level: 3, + Title: sectionAaTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + types.Section{ + Attributes: types.ElementAttributes{ + types.AttrID: "_section_a_b", + }, + Level: 3, + Title: sectionBTitle, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph"}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + result, err := rearrangeSections(actual) + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(expected)) + }) + +}) diff --git a/pkg/parser/document_processing_test.go b/pkg/parser/document_processing_test.go deleted file mode 100644 index 2d647fd5..00000000 --- a/pkg/parser/document_processing_test.go +++ /dev/null @@ -1,109 +0,0 @@ -package parser_test - -import ( - "github.com/bytesparadise/libasciidoc/pkg/parser" - "github.com/bytesparadise/libasciidoc/pkg/types" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("attribute subsititutions", func() { - - It("should replace with new StringElement on first position", func() { - // given - e := []interface{}{ - types.DocumentAttributeSubstitution{ - Name: "foo", - }, - types.StringElement{ - Content: " and more content.", - }, - } - // when - result, err := parser.ApplyDocumentAttributeSubstitutions(e, types.DocumentAttributes{ - "foo": "bar", - }) - // then - Expect(result).To(Equal([]interface{}{ - types.StringElement{ - Content: "bar and more content.", - }, - })) - Expect(err).To(Not(HaveOccurred())) - }) - - It("should replace with new StringElement on middle position", func() { - // given - e := []interface{}{ - types.StringElement{ - Content: "baz, ", - }, - types.DocumentAttributeSubstitution{ - Name: "foo", - }, - types.StringElement{ - Content: " and more content.", - }, - } - // when - result, err := parser.ApplyDocumentAttributeSubstitutions(e, types.DocumentAttributes{ - "foo": "bar", - }) - // then - Expect(result).To(Equal([]interface{}{ - types.StringElement{ - Content: "baz, bar and more content.", - }, - })) - Expect(err).To(Not(HaveOccurred())) - }) - - It("should replace with undefined attribute", func() { - // given - e := []interface{}{ - types.StringElement{ - Content: "baz, ", - }, - types.DocumentAttributeSubstitution{ - Name: "foo", - }, - types.StringElement{ - Content: " and more content.", - }, - } - // when - result, err := parser.ApplyDocumentAttributeSubstitutions(e, types.DocumentAttributes{}) - // then - Expect(result).To(Equal([]interface{}{ - types.StringElement{ - Content: "baz, {foo} and more content.", - }, - })) - Expect(err).To(Not(HaveOccurred())) - }) - - It("should merge without substitution", func() { - // given - e := []interface{}{ - types.StringElement{ - Content: "baz, ", - }, - types.StringElement{ - Content: "foo", - }, - types.StringElement{ - Content: " and more content.", - }, - } - // when - result, err := parser.ApplyDocumentAttributeSubstitutions(e, types.DocumentAttributes{}) - // then - Expect(result).To(Equal([]interface{}{ - types.StringElement{ - Content: "baz, foo and more content.", - }, - })) - Expect(err).To(Not(HaveOccurred())) - }) -}) diff --git a/pkg/parser/mixed_lists_test.go b/pkg/parser/mixed_lists_test.go index 6beb3edf..3a4d20ba 100644 --- a/pkg/parser/mixed_lists_test.go +++ b/pkg/parser/mixed_lists_test.go @@ -1561,8 +1561,8 @@ a paragraph It("same list with single comment line inside", func() { source := `. a - // - - . b` +// - +. b` expected := types.Document{ Attributes: types.DocumentAttributes{}, ElementReferences: types.ElementReferences{}, @@ -1587,9 +1587,6 @@ a paragraph }, }, }, - types.SingleLineComment{ - Content: " -", - }, }, }, { @@ -1618,10 +1615,10 @@ a paragraph It("same list with multiple comment lines inside", func() { source := `. a - // - - // - - // - - . b` +// - +// - +// - +. b` expected := types.Document{ Attributes: types.DocumentAttributes{}, ElementReferences: types.ElementReferences{}, @@ -1646,15 +1643,6 @@ a paragraph }, }, }, - types.SingleLineComment{ - Content: " -", - }, - types.SingleLineComment{ - Content: " -", - }, - types.SingleLineComment{ - Content: " -", - }, }, }, { @@ -1684,8 +1672,8 @@ a paragraph It("distinct lists separated by single comment line", func() { source := `. a - // - - . b` +// - +. b` expected := types.Document{ Attributes: types.DocumentAttributes{}, ElementReferences: types.ElementReferences{}, @@ -1714,9 +1702,6 @@ a paragraph }, }, }, - types.SingleLineComment{ - Content: " -", - }, types.OrderedList{ Attributes: types.ElementAttributes{}, Items: []types.OrderedListItem{ @@ -1779,15 +1764,6 @@ a paragraph }, }, }, - types.SingleLineComment{ - Content: " -", - }, - types.SingleLineComment{ - Content: " -", - }, - types.SingleLineComment{ - Content: " -", - }, types.OrderedList{ Attributes: types.ElementAttributes{}, Items: []types.OrderedListItem{ diff --git a/pkg/parser/ordered_list_test.go b/pkg/parser/ordered_list_test.go index 44a3a21c..bf7c579e 100644 --- a/pkg/parser/ordered_list_test.go +++ b/pkg/parser/ordered_list_test.go @@ -933,6 +933,92 @@ another delimited block } Expect(source).To(BecomeDraftDocument(expected)) }) + + It("ordered list with item continuation - case 2", func() { + source := `. {blank} ++ +---- +print("one") +---- +. {blank} ++ +---- +print("one") +----` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.DocumentAttributeSubstitution{ + Name: "blank", + }, + }, + }, + }, + }, + }, + types.ContinuedListItemElement{ + Offset: 0, + Element: types.DelimitedBlock{ + Kind: types.Listing, + Attributes: types.ElementAttributes{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "print(\"one\")"}, + }, + }, + }, + }, + }, + }, + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.DocumentAttributeSubstitution{ + Name: "blank", + }, + }, + }, + }, + }, + }, + types.ContinuedListItemElement{ + Offset: 0, + Element: types.DelimitedBlock{ + Kind: types.Listing, + Attributes: types.ElementAttributes{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "print(\"one\")"}, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) }) @@ -2128,5 +2214,82 @@ another delimited block } Expect(source).To(BecomeDocument(expected)) }) + + It("ordered list with item continuation - case 2", func() { + source := `. {blank} ++ +---- +print("one") +---- +. {blank} ++ +---- +print("one") +----` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.OrderedList{ + Attributes: types.ElementAttributes{}, + Items: []types.OrderedListItem{ + { + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{}, + }, + types.DelimitedBlock{ + Kind: types.Listing, + Attributes: types.ElementAttributes{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "print(\"one\")"}, + }, + }, + }, + }, + }, + }, + }, + types.OrderedListItem{ + Attributes: types.ElementAttributes{}, + Level: 1, + NumberingStyle: types.Arabic, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{}, + }, + types.DelimitedBlock{ + Kind: types.Listing, + Attributes: types.ElementAttributes{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "print(\"one\")"}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) }) }) diff --git a/pkg/parser/paragraph_test.go b/pkg/parser/paragraph_test.go index 1a70d7a0..770ad89a 100644 --- a/pkg/parser/paragraph_test.go +++ b/pkg/parser/paragraph_test.go @@ -8,9 +8,9 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("paragraphs - draft", func() { +var _ = Describe("paragraphs", func() { - Context("paragraphs", func() { + Context("default paragraphs", func() { It("paragraph with 1 word", func() { source := "hello" @@ -153,6 +153,23 @@ a paragraph` } Expect(source).To(BecomeDocument(expected)) }) + + It("empty paragraph", func() { + source := `{blank}` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{}, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) }) Context("paragraphs with line break", func() { @@ -678,9 +695,6 @@ image::foo.png[]` Expect(source).To(BecomeDocumentBlock(expected)) //, parser.Debug(true)) }) }) -}) - -var _ = Describe("paragraphs - final document", func() { It("paragraph with predefined attribute", func() { source := "hello {plus} world" @@ -702,4 +716,5 @@ var _ = Describe("paragraphs - final document", func() { } Expect(source).To(BecomeDocument(expected)) }) + }) diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index 0c65f82d..6b008582 100644 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -9100,6 +9100,10 @@ var g = &grammar{ pos: position{line: 1148, col: 11, offset: 42966}, name: "Parenthesis", }, + &ruleRefExpr{ + pos: position{line: 1149, col: 11, offset: 42988}, + name: "NEWLINE", + }, }, }, }, @@ -9108,16 +9112,16 @@ var g = &grammar{ }, { name: "ResolvedLink", - pos: position{line: 1152, col: 1, offset: 43046}, + pos: position{line: 1153, col: 1, offset: 43064}, expr: &choiceExpr{ - pos: position{line: 1152, col: 17, offset: 43062}, + pos: position{line: 1153, col: 17, offset: 43080}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1152, col: 17, offset: 43062}, + pos: position{line: 1153, col: 17, offset: 43080}, name: "ResolvedRelativeLink", }, &ruleRefExpr{ - pos: position{line: 1152, col: 40, offset: 43085}, + pos: position{line: 1153, col: 40, offset: 43103}, name: "ResolvedExternalLink", }, }, @@ -9125,40 +9129,40 @@ var g = &grammar{ }, { name: "ResolvedRelativeLink", - pos: position{line: 1155, col: 1, offset: 43221}, + pos: position{line: 1156, col: 1, offset: 43239}, expr: &actionExpr{ - pos: position{line: 1155, col: 25, offset: 43245}, + pos: position{line: 1156, col: 25, offset: 43263}, run: (*parser).callonResolvedRelativeLink1, expr: &seqExpr{ - pos: position{line: 1155, col: 25, offset: 43245}, + pos: position{line: 1156, col: 25, offset: 43263}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1155, col: 25, offset: 43245}, + pos: position{line: 1156, col: 25, offset: 43263}, val: "link:", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 1155, col: 33, offset: 43253}, + pos: position{line: 1156, col: 33, offset: 43271}, label: "url", expr: &choiceExpr{ - pos: position{line: 1155, col: 38, offset: 43258}, + pos: position{line: 1156, col: 38, offset: 43276}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1155, col: 38, offset: 43258}, + pos: position{line: 1156, col: 38, offset: 43276}, name: "ResolvedLocation", }, &ruleRefExpr{ - pos: position{line: 1155, col: 57, offset: 43277}, + pos: position{line: 1156, col: 57, offset: 43295}, name: "ResolvedFileLocation", }, }, }, }, &labeledExpr{ - pos: position{line: 1155, col: 79, offset: 43299}, + pos: position{line: 1156, col: 79, offset: 43317}, label: "inlineAttributes", expr: &ruleRefExpr{ - pos: position{line: 1155, col: 97, offset: 43317}, + pos: position{line: 1156, col: 97, offset: 43335}, name: "LinkAttributes", }, }, @@ -9168,28 +9172,28 @@ var g = &grammar{ }, { name: "ResolvedExternalLink", - pos: position{line: 1159, col: 1, offset: 43435}, + pos: position{line: 1160, col: 1, offset: 43453}, expr: &actionExpr{ - pos: position{line: 1159, col: 25, offset: 43459}, + pos: position{line: 1160, col: 25, offset: 43477}, run: (*parser).callonResolvedExternalLink1, expr: &seqExpr{ - pos: position{line: 1159, col: 25, offset: 43459}, + pos: position{line: 1160, col: 25, offset: 43477}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1159, col: 25, offset: 43459}, + pos: position{line: 1160, col: 25, offset: 43477}, label: "url", expr: &ruleRefExpr{ - pos: position{line: 1159, col: 30, offset: 43464}, + pos: position{line: 1160, col: 30, offset: 43482}, name: "ResolvedLocation", }, }, &labeledExpr{ - pos: position{line: 1159, col: 48, offset: 43482}, + pos: position{line: 1160, col: 48, offset: 43500}, label: "inlineAttributes", expr: &zeroOrOneExpr{ - pos: position{line: 1159, col: 65, offset: 43499}, + pos: position{line: 1160, col: 65, offset: 43517}, expr: &ruleRefExpr{ - pos: position{line: 1159, col: 66, offset: 43500}, + pos: position{line: 1160, col: 66, offset: 43518}, name: "LinkAttributes", }, }, @@ -9200,56 +9204,56 @@ var g = &grammar{ }, { name: "ImageBlock", - pos: position{line: 1168, col: 1, offset: 43697}, + pos: position{line: 1169, col: 1, offset: 43715}, expr: &actionExpr{ - pos: position{line: 1168, col: 15, offset: 43711}, + pos: position{line: 1169, col: 15, offset: 43729}, run: (*parser).callonImageBlock1, expr: &seqExpr{ - pos: position{line: 1168, col: 15, offset: 43711}, + pos: position{line: 1169, col: 15, offset: 43729}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1168, col: 15, offset: 43711}, + pos: position{line: 1169, col: 15, offset: 43729}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 1168, col: 26, offset: 43722}, + pos: position{line: 1169, col: 26, offset: 43740}, expr: &ruleRefExpr{ - pos: position{line: 1168, col: 27, offset: 43723}, + pos: position{line: 1169, col: 27, offset: 43741}, name: "ElementAttributes", }, }, }, &litMatcher{ - pos: position{line: 1168, col: 47, offset: 43743}, + pos: position{line: 1169, col: 47, offset: 43761}, val: "image::", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 1168, col: 57, offset: 43753}, + pos: position{line: 1169, col: 57, offset: 43771}, label: "path", expr: &choiceExpr{ - pos: position{line: 1168, col: 63, offset: 43759}, + pos: position{line: 1169, col: 63, offset: 43777}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1168, col: 63, offset: 43759}, + pos: position{line: 1169, col: 63, offset: 43777}, name: "Location", }, &ruleRefExpr{ - pos: position{line: 1168, col: 74, offset: 43770}, + pos: position{line: 1169, col: 74, offset: 43788}, name: "FileLocation", }, }, }, }, &labeledExpr{ - pos: position{line: 1168, col: 88, offset: 43784}, + pos: position{line: 1169, col: 88, offset: 43802}, label: "inlineAttributes", expr: &ruleRefExpr{ - pos: position{line: 1168, col: 106, offset: 43802}, + pos: position{line: 1169, col: 106, offset: 43820}, name: "ImageAttributes", }, }, &ruleRefExpr{ - pos: position{line: 1168, col: 123, offset: 43819}, + pos: position{line: 1169, col: 123, offset: 43837}, name: "EOLS", }, }, @@ -9258,48 +9262,48 @@ var g = &grammar{ }, { name: "InlineImage", - pos: position{line: 1172, col: 1, offset: 43939}, + pos: position{line: 1173, col: 1, offset: 43957}, expr: &actionExpr{ - pos: position{line: 1172, col: 16, offset: 43954}, + pos: position{line: 1173, col: 16, offset: 43972}, run: (*parser).callonInlineImage1, expr: &seqExpr{ - pos: position{line: 1172, col: 16, offset: 43954}, + pos: position{line: 1173, col: 16, offset: 43972}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1172, col: 16, offset: 43954}, + pos: position{line: 1173, col: 16, offset: 43972}, val: "image:", ignoreCase: false, }, ¬Expr{ - pos: position{line: 1172, col: 25, offset: 43963}, + pos: position{line: 1173, col: 25, offset: 43981}, expr: &litMatcher{ - pos: position{line: 1172, col: 26, offset: 43964}, + pos: position{line: 1173, col: 26, offset: 43982}, val: ":", ignoreCase: false, }, }, &labeledExpr{ - pos: position{line: 1172, col: 30, offset: 43968}, + pos: position{line: 1173, col: 30, offset: 43986}, label: "path", expr: &choiceExpr{ - pos: position{line: 1172, col: 36, offset: 43974}, + pos: position{line: 1173, col: 36, offset: 43992}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1172, col: 36, offset: 43974}, + pos: position{line: 1173, col: 36, offset: 43992}, name: "Location", }, &ruleRefExpr{ - pos: position{line: 1172, col: 47, offset: 43985}, + pos: position{line: 1173, col: 47, offset: 44003}, name: "FileLocation", }, }, }, }, &labeledExpr{ - pos: position{line: 1172, col: 61, offset: 43999}, + pos: position{line: 1173, col: 61, offset: 44017}, label: "inlineAttributes", expr: &ruleRefExpr{ - pos: position{line: 1172, col: 79, offset: 44017}, + pos: position{line: 1173, col: 79, offset: 44035}, name: "ImageAttributes", }, }, @@ -9309,95 +9313,95 @@ var g = &grammar{ }, { name: "ImageAttributes", - pos: position{line: 1176, col: 1, offset: 44138}, + pos: position{line: 1177, col: 1, offset: 44156}, expr: &actionExpr{ - pos: position{line: 1176, col: 20, offset: 44157}, + pos: position{line: 1177, col: 20, offset: 44175}, run: (*parser).callonImageAttributes1, expr: &seqExpr{ - pos: position{line: 1176, col: 20, offset: 44157}, + pos: position{line: 1177, col: 20, offset: 44175}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1176, col: 20, offset: 44157}, + pos: position{line: 1177, col: 20, offset: 44175}, val: "[", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 1176, col: 24, offset: 44161}, + pos: position{line: 1177, col: 24, offset: 44179}, label: "alt", expr: &zeroOrOneExpr{ - pos: position{line: 1176, col: 28, offset: 44165}, + pos: position{line: 1177, col: 28, offset: 44183}, expr: &ruleRefExpr{ - pos: position{line: 1176, col: 29, offset: 44166}, + pos: position{line: 1177, col: 29, offset: 44184}, name: "AttributeValue", }, }, }, &zeroOrOneExpr{ - pos: position{line: 1176, col: 46, offset: 44183}, + pos: position{line: 1177, col: 46, offset: 44201}, expr: &litMatcher{ - pos: position{line: 1176, col: 46, offset: 44183}, + pos: position{line: 1177, col: 46, offset: 44201}, val: ",", ignoreCase: false, }, }, &labeledExpr{ - pos: position{line: 1176, col: 51, offset: 44188}, + pos: position{line: 1177, col: 51, offset: 44206}, label: "width", expr: &zeroOrOneExpr{ - pos: position{line: 1176, col: 57, offset: 44194}, + pos: position{line: 1177, col: 57, offset: 44212}, expr: &ruleRefExpr{ - pos: position{line: 1176, col: 58, offset: 44195}, + pos: position{line: 1177, col: 58, offset: 44213}, name: "AttributeValue", }, }, }, &zeroOrOneExpr{ - pos: position{line: 1176, col: 75, offset: 44212}, + pos: position{line: 1177, col: 75, offset: 44230}, expr: &litMatcher{ - pos: position{line: 1176, col: 75, offset: 44212}, + pos: position{line: 1177, col: 75, offset: 44230}, val: ",", ignoreCase: false, }, }, &labeledExpr{ - pos: position{line: 1176, col: 80, offset: 44217}, + pos: position{line: 1177, col: 80, offset: 44235}, label: "height", expr: &zeroOrOneExpr{ - pos: position{line: 1176, col: 87, offset: 44224}, + pos: position{line: 1177, col: 87, offset: 44242}, expr: &ruleRefExpr{ - pos: position{line: 1176, col: 88, offset: 44225}, + pos: position{line: 1177, col: 88, offset: 44243}, name: "AttributeValue", }, }, }, &zeroOrOneExpr{ - pos: position{line: 1176, col: 105, offset: 44242}, + pos: position{line: 1177, col: 105, offset: 44260}, expr: &litMatcher{ - pos: position{line: 1176, col: 105, offset: 44242}, + pos: position{line: 1177, col: 105, offset: 44260}, val: ",", ignoreCase: false, }, }, &zeroOrMoreExpr{ - pos: position{line: 1176, col: 110, offset: 44247}, + pos: position{line: 1177, col: 110, offset: 44265}, expr: &ruleRefExpr{ - pos: position{line: 1176, col: 110, offset: 44247}, + pos: position{line: 1177, col: 110, offset: 44265}, name: "WS", }, }, &labeledExpr{ - pos: position{line: 1176, col: 114, offset: 44251}, + pos: position{line: 1177, col: 114, offset: 44269}, label: "otherattrs", expr: &zeroOrMoreExpr{ - pos: position{line: 1176, col: 125, offset: 44262}, + pos: position{line: 1177, col: 125, offset: 44280}, expr: &ruleRefExpr{ - pos: position{line: 1176, col: 126, offset: 44263}, + pos: position{line: 1177, col: 126, offset: 44281}, name: "GenericAttribute", }, }, }, &litMatcher{ - pos: position{line: 1176, col: 145, offset: 44282}, + pos: position{line: 1177, col: 145, offset: 44300}, val: "]", ignoreCase: false, }, @@ -9407,31 +9411,31 @@ var g = &grammar{ }, { name: "InlineFootnote", - pos: position{line: 1183, col: 1, offset: 44572}, + pos: position{line: 1184, col: 1, offset: 44590}, expr: &choiceExpr{ - pos: position{line: 1183, col: 19, offset: 44590}, + pos: position{line: 1184, col: 19, offset: 44608}, alternatives: []interface{}{ &actionExpr{ - pos: position{line: 1183, col: 19, offset: 44590}, + pos: position{line: 1184, col: 19, offset: 44608}, run: (*parser).callonInlineFootnote2, expr: &seqExpr{ - pos: position{line: 1183, col: 19, offset: 44590}, + pos: position{line: 1184, col: 19, offset: 44608}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1183, col: 19, offset: 44590}, + pos: position{line: 1184, col: 19, offset: 44608}, val: "footnote:[", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 1183, col: 32, offset: 44603}, + pos: position{line: 1184, col: 32, offset: 44621}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 1183, col: 41, offset: 44612}, + pos: position{line: 1184, col: 41, offset: 44630}, name: "FootnoteContent", }, }, &litMatcher{ - pos: position{line: 1183, col: 58, offset: 44629}, + pos: position{line: 1184, col: 58, offset: 44647}, val: "]", ignoreCase: false, }, @@ -9439,39 +9443,39 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 1185, col: 5, offset: 44697}, + pos: position{line: 1186, col: 5, offset: 44715}, run: (*parser).callonInlineFootnote8, expr: &seqExpr{ - pos: position{line: 1185, col: 5, offset: 44697}, + pos: position{line: 1186, col: 5, offset: 44715}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1185, col: 5, offset: 44697}, + pos: position{line: 1186, col: 5, offset: 44715}, val: "footnoteref:[", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 1185, col: 21, offset: 44713}, + pos: position{line: 1186, col: 21, offset: 44731}, label: "ref", expr: &ruleRefExpr{ - pos: position{line: 1185, col: 26, offset: 44718}, + pos: position{line: 1186, col: 26, offset: 44736}, name: "FootnoteRef", }, }, &litMatcher{ - pos: position{line: 1185, col: 39, offset: 44731}, + pos: position{line: 1186, col: 39, offset: 44749}, val: ",", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 1185, col: 43, offset: 44735}, + pos: position{line: 1186, col: 43, offset: 44753}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 1185, col: 52, offset: 44744}, + pos: position{line: 1186, col: 52, offset: 44762}, name: "FootnoteContent", }, }, &litMatcher{ - pos: position{line: 1185, col: 69, offset: 44761}, + pos: position{line: 1186, col: 69, offset: 44779}, val: "]", ignoreCase: false, }, @@ -9479,26 +9483,26 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 1187, col: 5, offset: 44839}, + pos: position{line: 1188, col: 5, offset: 44857}, run: (*parser).callonInlineFootnote17, expr: &seqExpr{ - pos: position{line: 1187, col: 5, offset: 44839}, + pos: position{line: 1188, col: 5, offset: 44857}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1187, col: 5, offset: 44839}, + pos: position{line: 1188, col: 5, offset: 44857}, val: "footnoteref:[", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 1187, col: 21, offset: 44855}, + pos: position{line: 1188, col: 21, offset: 44873}, label: "ref", expr: &ruleRefExpr{ - pos: position{line: 1187, col: 26, offset: 44860}, + pos: position{line: 1188, col: 26, offset: 44878}, name: "FootnoteRef", }, }, &litMatcher{ - pos: position{line: 1187, col: 39, offset: 44873}, + pos: position{line: 1188, col: 39, offset: 44891}, val: "]", ignoreCase: false, }, @@ -9510,51 +9514,51 @@ var g = &grammar{ }, { name: "FootnoteRef", - pos: position{line: 1191, col: 1, offset: 44981}, + pos: position{line: 1192, col: 1, offset: 44999}, expr: &actionExpr{ - pos: position{line: 1191, col: 16, offset: 44996}, + pos: position{line: 1192, col: 16, offset: 45014}, run: (*parser).callonFootnoteRef1, expr: &zeroOrMoreExpr{ - pos: position{line: 1191, col: 16, offset: 44996}, + pos: position{line: 1192, col: 16, offset: 45014}, expr: &choiceExpr{ - pos: position{line: 1191, col: 17, offset: 44997}, + pos: position{line: 1192, col: 17, offset: 45015}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1191, col: 17, offset: 44997}, + pos: position{line: 1192, col: 17, offset: 45015}, name: "Alphanums", }, &ruleRefExpr{ - pos: position{line: 1191, col: 29, offset: 45009}, + pos: position{line: 1192, col: 29, offset: 45027}, name: "Spaces", }, &seqExpr{ - pos: position{line: 1191, col: 39, offset: 45019}, + pos: position{line: 1192, col: 39, offset: 45037}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1191, col: 39, offset: 45019}, + pos: position{line: 1192, col: 39, offset: 45037}, expr: &litMatcher{ - pos: position{line: 1191, col: 40, offset: 45020}, + pos: position{line: 1192, col: 40, offset: 45038}, val: ",", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 1191, col: 44, offset: 45024}, + pos: position{line: 1192, col: 44, offset: 45042}, expr: &litMatcher{ - pos: position{line: 1191, col: 45, offset: 45025}, + pos: position{line: 1192, col: 45, offset: 45043}, val: "]", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 1191, col: 49, offset: 45029}, + pos: position{line: 1192, col: 49, offset: 45047}, expr: &ruleRefExpr{ - pos: position{line: 1191, col: 50, offset: 45030}, + pos: position{line: 1192, col: 50, offset: 45048}, name: "EOL", }, }, &anyMatcher{ - line: 1191, col: 55, offset: 45035, + line: 1192, col: 55, offset: 45053, }, }, }, @@ -9565,55 +9569,55 @@ var g = &grammar{ }, { name: "FootnoteContent", - pos: position{line: 1195, col: 1, offset: 45120}, + pos: position{line: 1196, col: 1, offset: 45138}, expr: &actionExpr{ - pos: position{line: 1195, col: 20, offset: 45139}, + pos: position{line: 1196, col: 20, offset: 45157}, run: (*parser).callonFootnoteContent1, expr: &labeledExpr{ - pos: position{line: 1195, col: 20, offset: 45139}, + pos: position{line: 1196, col: 20, offset: 45157}, label: "elements", expr: &oneOrMoreExpr{ - pos: position{line: 1195, col: 29, offset: 45148}, + pos: position{line: 1196, col: 29, offset: 45166}, expr: &seqExpr{ - pos: position{line: 1195, col: 30, offset: 45149}, + pos: position{line: 1196, col: 30, offset: 45167}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1195, col: 30, offset: 45149}, + pos: position{line: 1196, col: 30, offset: 45167}, expr: &litMatcher{ - pos: position{line: 1195, col: 31, offset: 45150}, + pos: position{line: 1196, col: 31, offset: 45168}, val: "]", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 1195, col: 35, offset: 45154}, + pos: position{line: 1196, col: 35, offset: 45172}, expr: &ruleRefExpr{ - pos: position{line: 1195, col: 36, offset: 45155}, + pos: position{line: 1196, col: 36, offset: 45173}, name: "EOL", }, }, &zeroOrMoreExpr{ - pos: position{line: 1195, col: 40, offset: 45159}, + pos: position{line: 1196, col: 40, offset: 45177}, expr: &ruleRefExpr{ - pos: position{line: 1195, col: 40, offset: 45159}, + pos: position{line: 1196, col: 40, offset: 45177}, name: "WS", }, }, ¬Expr{ - pos: position{line: 1195, col: 44, offset: 45163}, + pos: position{line: 1196, col: 44, offset: 45181}, expr: &ruleRefExpr{ - pos: position{line: 1195, col: 45, offset: 45164}, + pos: position{line: 1196, col: 45, offset: 45182}, name: "InlineElementID", }, }, &ruleRefExpr{ - pos: position{line: 1195, col: 61, offset: 45180}, + pos: position{line: 1196, col: 61, offset: 45198}, name: "InlineElement", }, &zeroOrMoreExpr{ - pos: position{line: 1195, col: 75, offset: 45194}, + pos: position{line: 1196, col: 75, offset: 45212}, expr: &ruleRefExpr{ - pos: position{line: 1195, col: 75, offset: 45194}, + pos: position{line: 1196, col: 75, offset: 45212}, name: "WS", }, }, @@ -9625,60 +9629,60 @@ var g = &grammar{ }, { name: "DelimitedBlock", - pos: position{line: 1202, col: 1, offset: 45508}, + pos: position{line: 1203, col: 1, offset: 45526}, expr: &actionExpr{ - pos: position{line: 1202, col: 19, offset: 45526}, + pos: position{line: 1203, col: 19, offset: 45544}, run: (*parser).callonDelimitedBlock1, expr: &seqExpr{ - pos: position{line: 1202, col: 19, offset: 45526}, + pos: position{line: 1203, col: 19, offset: 45544}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1202, col: 19, offset: 45526}, + pos: position{line: 1203, col: 19, offset: 45544}, expr: &ruleRefExpr{ - pos: position{line: 1202, col: 20, offset: 45527}, + pos: position{line: 1203, col: 20, offset: 45545}, name: "Alphanum", }, }, &labeledExpr{ - pos: position{line: 1203, col: 5, offset: 45556}, + pos: position{line: 1204, col: 5, offset: 45574}, label: "block", expr: &choiceExpr{ - pos: position{line: 1203, col: 12, offset: 45563}, + pos: position{line: 1204, col: 12, offset: 45581}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1203, col: 12, offset: 45563}, + pos: position{line: 1204, col: 12, offset: 45581}, name: "FencedBlock", }, &ruleRefExpr{ - pos: position{line: 1204, col: 11, offset: 45586}, + pos: position{line: 1205, col: 11, offset: 45604}, name: "ListingBlock", }, &ruleRefExpr{ - pos: position{line: 1205, col: 11, offset: 45610}, + pos: position{line: 1206, col: 11, offset: 45628}, name: "ExampleBlock", }, &ruleRefExpr{ - pos: position{line: 1206, col: 11, offset: 45634}, + pos: position{line: 1207, col: 11, offset: 45652}, name: "VerseBlock", }, &ruleRefExpr{ - pos: position{line: 1207, col: 11, offset: 45656}, + pos: position{line: 1208, col: 11, offset: 45674}, name: "QuoteBlock", }, &ruleRefExpr{ - pos: position{line: 1208, col: 11, offset: 45678}, + pos: position{line: 1209, col: 11, offset: 45696}, name: "SidebarBlock", }, &ruleRefExpr{ - pos: position{line: 1209, col: 11, offset: 45701}, + pos: position{line: 1210, col: 11, offset: 45719}, name: "SingleLineComment", }, &ruleRefExpr{ - pos: position{line: 1210, col: 11, offset: 45729}, + pos: position{line: 1211, col: 11, offset: 45747}, name: "Table", }, &ruleRefExpr{ - pos: position{line: 1211, col: 11, offset: 45745}, + pos: position{line: 1212, col: 11, offset: 45763}, name: "CommentBlock", }, }, @@ -9690,36 +9694,36 @@ var g = &grammar{ }, { name: "BlockDelimiter", - pos: position{line: 1215, col: 1, offset: 45786}, + pos: position{line: 1216, col: 1, offset: 45804}, expr: &choiceExpr{ - pos: position{line: 1215, col: 19, offset: 45804}, + pos: position{line: 1216, col: 19, offset: 45822}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1215, col: 19, offset: 45804}, + pos: position{line: 1216, col: 19, offset: 45822}, name: "LiteralBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1216, col: 19, offset: 45845}, + pos: position{line: 1217, col: 19, offset: 45863}, name: "FencedBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1217, col: 19, offset: 45885}, + pos: position{line: 1218, col: 19, offset: 45903}, name: "ListingBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1218, col: 19, offset: 45926}, + pos: position{line: 1219, col: 19, offset: 45944}, name: "ExampleBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1219, col: 19, offset: 45967}, + pos: position{line: 1220, col: 19, offset: 45985}, name: "CommentBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1220, col: 19, offset: 46008}, + pos: position{line: 1221, col: 19, offset: 46026}, name: "QuoteBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1221, col: 19, offset: 46046}, + pos: position{line: 1222, col: 19, offset: 46064}, name: "SidebarBlockDelimiter", }, }, @@ -9727,17 +9731,17 @@ var g = &grammar{ }, { name: "FencedBlockDelimiter", - pos: position{line: 1227, col: 1, offset: 46265}, + pos: position{line: 1228, col: 1, offset: 46283}, expr: &seqExpr{ - pos: position{line: 1227, col: 25, offset: 46289}, + pos: position{line: 1228, col: 25, offset: 46307}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1227, col: 25, offset: 46289}, + pos: position{line: 1228, col: 25, offset: 46307}, val: "```", ignoreCase: false, }, &ruleRefExpr{ - pos: position{line: 1227, col: 31, offset: 46295}, + pos: position{line: 1228, col: 31, offset: 46313}, name: "EOLS", }, }, @@ -9745,48 +9749,48 @@ var g = &grammar{ }, { name: "FencedBlock", - pos: position{line: 1229, col: 1, offset: 46301}, + pos: position{line: 1230, col: 1, offset: 46319}, expr: &actionExpr{ - pos: position{line: 1229, col: 16, offset: 46316}, + pos: position{line: 1230, col: 16, offset: 46334}, run: (*parser).callonFencedBlock1, expr: &seqExpr{ - pos: position{line: 1229, col: 16, offset: 46316}, + pos: position{line: 1230, col: 16, offset: 46334}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1229, col: 16, offset: 46316}, + pos: position{line: 1230, col: 16, offset: 46334}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 1229, col: 27, offset: 46327}, + pos: position{line: 1230, col: 27, offset: 46345}, expr: &ruleRefExpr{ - pos: position{line: 1229, col: 28, offset: 46328}, + pos: position{line: 1230, col: 28, offset: 46346}, name: "ElementAttributes", }, }, }, &ruleRefExpr{ - pos: position{line: 1229, col: 48, offset: 46348}, + pos: position{line: 1230, col: 48, offset: 46366}, name: "FencedBlockDelimiter", }, &labeledExpr{ - pos: position{line: 1229, col: 69, offset: 46369}, + pos: position{line: 1230, col: 69, offset: 46387}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 1229, col: 77, offset: 46377}, + pos: position{line: 1230, col: 77, offset: 46395}, expr: &ruleRefExpr{ - pos: position{line: 1229, col: 78, offset: 46378}, + pos: position{line: 1230, col: 78, offset: 46396}, name: "FencedBlockContent", }, }, }, &choiceExpr{ - pos: position{line: 1229, col: 100, offset: 46400}, + pos: position{line: 1230, col: 100, offset: 46418}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1229, col: 100, offset: 46400}, + pos: position{line: 1230, col: 100, offset: 46418}, name: "FencedBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1229, col: 123, offset: 46423}, + pos: position{line: 1230, col: 123, offset: 46441}, name: "EOF", }, }, @@ -9797,24 +9801,24 @@ var g = &grammar{ }, { name: "FencedBlockContent", - pos: position{line: 1233, col: 1, offset: 46531}, + pos: position{line: 1234, col: 1, offset: 46549}, expr: &choiceExpr{ - pos: position{line: 1233, col: 23, offset: 46553}, + pos: position{line: 1234, col: 23, offset: 46571}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1233, col: 23, offset: 46553}, + pos: position{line: 1234, col: 23, offset: 46571}, name: "BlankLine", }, &ruleRefExpr{ - pos: position{line: 1233, col: 35, offset: 46565}, + pos: position{line: 1234, col: 35, offset: 46583}, name: "FileInclusion", }, &ruleRefExpr{ - pos: position{line: 1233, col: 51, offset: 46581}, + pos: position{line: 1234, col: 51, offset: 46599}, name: "ListItem", }, &ruleRefExpr{ - pos: position{line: 1233, col: 62, offset: 46592}, + pos: position{line: 1234, col: 62, offset: 46610}, name: "FencedBlockParagraph", }, }, @@ -9822,17 +9826,17 @@ var g = &grammar{ }, { name: "FencedBlockParagraph", - pos: position{line: 1236, col: 1, offset: 46632}, + pos: position{line: 1237, col: 1, offset: 46650}, expr: &actionExpr{ - pos: position{line: 1236, col: 25, offset: 46656}, + pos: position{line: 1237, col: 25, offset: 46674}, run: (*parser).callonFencedBlockParagraph1, expr: &labeledExpr{ - pos: position{line: 1236, col: 25, offset: 46656}, + pos: position{line: 1237, col: 25, offset: 46674}, label: "lines", expr: &oneOrMoreExpr{ - pos: position{line: 1236, col: 31, offset: 46662}, + pos: position{line: 1237, col: 31, offset: 46680}, expr: &ruleRefExpr{ - pos: position{line: 1236, col: 32, offset: 46663}, + pos: position{line: 1237, col: 32, offset: 46681}, name: "FencedBlockParagraphLine", }, }, @@ -9841,32 +9845,32 @@ var g = &grammar{ }, { name: "FencedBlockParagraphLine", - pos: position{line: 1240, col: 1, offset: 46776}, + pos: position{line: 1241, col: 1, offset: 46794}, expr: &actionExpr{ - pos: position{line: 1240, col: 29, offset: 46804}, + pos: position{line: 1241, col: 29, offset: 46822}, run: (*parser).callonFencedBlockParagraphLine1, expr: &seqExpr{ - pos: position{line: 1240, col: 29, offset: 46804}, + pos: position{line: 1241, col: 29, offset: 46822}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1240, col: 29, offset: 46804}, + pos: position{line: 1241, col: 29, offset: 46822}, expr: &ruleRefExpr{ - pos: position{line: 1240, col: 30, offset: 46805}, + pos: position{line: 1241, col: 30, offset: 46823}, name: "FencedBlockDelimiter", }, }, ¬Expr{ - pos: position{line: 1240, col: 51, offset: 46826}, + pos: position{line: 1241, col: 51, offset: 46844}, expr: &ruleRefExpr{ - pos: position{line: 1240, col: 52, offset: 46827}, + pos: position{line: 1241, col: 52, offset: 46845}, name: "BlankLine", }, }, &labeledExpr{ - pos: position{line: 1240, col: 62, offset: 46837}, + pos: position{line: 1241, col: 62, offset: 46855}, label: "line", expr: &ruleRefExpr{ - pos: position{line: 1240, col: 68, offset: 46843}, + pos: position{line: 1241, col: 68, offset: 46861}, name: "InlineElements", }, }, @@ -9876,17 +9880,17 @@ var g = &grammar{ }, { name: "ListingBlockDelimiter", - pos: position{line: 1247, col: 1, offset: 47081}, + pos: position{line: 1248, col: 1, offset: 47099}, expr: &seqExpr{ - pos: position{line: 1247, col: 26, offset: 47106}, + pos: position{line: 1248, col: 26, offset: 47124}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1247, col: 26, offset: 47106}, + pos: position{line: 1248, col: 26, offset: 47124}, val: "----", ignoreCase: false, }, &ruleRefExpr{ - pos: position{line: 1247, col: 33, offset: 47113}, + pos: position{line: 1248, col: 33, offset: 47131}, name: "EOLS", }, }, @@ -9894,48 +9898,48 @@ var g = &grammar{ }, { name: "ListingBlock", - pos: position{line: 1249, col: 1, offset: 47119}, + pos: position{line: 1250, col: 1, offset: 47137}, expr: &actionExpr{ - pos: position{line: 1249, col: 17, offset: 47135}, + pos: position{line: 1250, col: 17, offset: 47153}, run: (*parser).callonListingBlock1, expr: &seqExpr{ - pos: position{line: 1249, col: 17, offset: 47135}, + pos: position{line: 1250, col: 17, offset: 47153}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1249, col: 17, offset: 47135}, + pos: position{line: 1250, col: 17, offset: 47153}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 1249, col: 28, offset: 47146}, + pos: position{line: 1250, col: 28, offset: 47164}, expr: &ruleRefExpr{ - pos: position{line: 1249, col: 29, offset: 47147}, + pos: position{line: 1250, col: 29, offset: 47165}, name: "ElementAttributes", }, }, }, &ruleRefExpr{ - pos: position{line: 1249, col: 49, offset: 47167}, + pos: position{line: 1250, col: 49, offset: 47185}, name: "ListingBlockDelimiter", }, &labeledExpr{ - pos: position{line: 1249, col: 71, offset: 47189}, + pos: position{line: 1250, col: 71, offset: 47207}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 1249, col: 79, offset: 47197}, + pos: position{line: 1250, col: 79, offset: 47215}, expr: &ruleRefExpr{ - pos: position{line: 1249, col: 80, offset: 47198}, + pos: position{line: 1250, col: 80, offset: 47216}, name: "ListingBlockElement", }, }, }, &choiceExpr{ - pos: position{line: 1249, col: 103, offset: 47221}, + pos: position{line: 1250, col: 103, offset: 47239}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1249, col: 103, offset: 47221}, + pos: position{line: 1250, col: 103, offset: 47239}, name: "ListingBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1249, col: 127, offset: 47245}, + pos: position{line: 1250, col: 127, offset: 47263}, name: "EOF", }, }, @@ -9946,16 +9950,16 @@ var g = &grammar{ }, { name: "ListingBlockElement", - pos: position{line: 1253, col: 1, offset: 47354}, + pos: position{line: 1254, col: 1, offset: 47372}, expr: &choiceExpr{ - pos: position{line: 1253, col: 24, offset: 47377}, + pos: position{line: 1254, col: 24, offset: 47395}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1253, col: 24, offset: 47377}, + pos: position{line: 1254, col: 24, offset: 47395}, name: "FileInclusion", }, &ruleRefExpr{ - pos: position{line: 1253, col: 40, offset: 47393}, + pos: position{line: 1254, col: 40, offset: 47411}, name: "ListingBlockParagraph", }, }, @@ -9963,17 +9967,17 @@ var g = &grammar{ }, { name: "ListingBlockParagraph", - pos: position{line: 1255, col: 1, offset: 47416}, + pos: position{line: 1256, col: 1, offset: 47434}, expr: &actionExpr{ - pos: position{line: 1255, col: 26, offset: 47441}, + pos: position{line: 1256, col: 26, offset: 47459}, run: (*parser).callonListingBlockParagraph1, expr: &labeledExpr{ - pos: position{line: 1255, col: 26, offset: 47441}, + pos: position{line: 1256, col: 26, offset: 47459}, label: "lines", expr: &oneOrMoreExpr{ - pos: position{line: 1255, col: 32, offset: 47447}, + pos: position{line: 1256, col: 32, offset: 47465}, expr: &ruleRefExpr{ - pos: position{line: 1255, col: 33, offset: 47448}, + pos: position{line: 1256, col: 33, offset: 47466}, name: "ListingBlockParagraphLine", }, }, @@ -9982,61 +9986,61 @@ var g = &grammar{ }, { name: "ListingBlockParagraphLine", - pos: position{line: 1259, col: 1, offset: 47567}, + pos: position{line: 1260, col: 1, offset: 47585}, expr: &actionExpr{ - pos: position{line: 1259, col: 30, offset: 47596}, + pos: position{line: 1260, col: 30, offset: 47614}, run: (*parser).callonListingBlockParagraphLine1, expr: &seqExpr{ - pos: position{line: 1259, col: 30, offset: 47596}, + pos: position{line: 1260, col: 30, offset: 47614}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1259, col: 30, offset: 47596}, + pos: position{line: 1260, col: 30, offset: 47614}, expr: &ruleRefExpr{ - pos: position{line: 1259, col: 31, offset: 47597}, + pos: position{line: 1260, col: 31, offset: 47615}, name: "ListingBlockDelimiter", }, }, &labeledExpr{ - pos: position{line: 1259, col: 53, offset: 47619}, + pos: position{line: 1260, col: 53, offset: 47637}, label: "line", expr: &actionExpr{ - pos: position{line: 1259, col: 59, offset: 47625}, + pos: position{line: 1260, col: 59, offset: 47643}, run: (*parser).callonListingBlockParagraphLine6, expr: &seqExpr{ - pos: position{line: 1259, col: 59, offset: 47625}, + pos: position{line: 1260, col: 59, offset: 47643}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1259, col: 59, offset: 47625}, + pos: position{line: 1260, col: 59, offset: 47643}, expr: &ruleRefExpr{ - pos: position{line: 1259, col: 60, offset: 47626}, + pos: position{line: 1260, col: 60, offset: 47644}, name: "EOF", }, }, &zeroOrMoreExpr{ - pos: position{line: 1259, col: 64, offset: 47630}, + pos: position{line: 1260, col: 64, offset: 47648}, expr: &choiceExpr{ - pos: position{line: 1259, col: 65, offset: 47631}, + pos: position{line: 1260, col: 65, offset: 47649}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1259, col: 65, offset: 47631}, + pos: position{line: 1260, col: 65, offset: 47649}, name: "Alphanums", }, &ruleRefExpr{ - pos: position{line: 1259, col: 77, offset: 47643}, + pos: position{line: 1260, col: 77, offset: 47661}, name: "Spaces", }, &seqExpr{ - pos: position{line: 1259, col: 87, offset: 47653}, + pos: position{line: 1260, col: 87, offset: 47671}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1259, col: 87, offset: 47653}, + pos: position{line: 1260, col: 87, offset: 47671}, expr: &ruleRefExpr{ - pos: position{line: 1259, col: 88, offset: 47654}, + pos: position{line: 1260, col: 88, offset: 47672}, name: "EOL", }, }, &anyMatcher{ - line: 1259, col: 92, offset: 47658, + line: 1260, col: 92, offset: 47676, }, }, }, @@ -10048,7 +10052,7 @@ var g = &grammar{ }, }, &ruleRefExpr{ - pos: position{line: 1259, col: 128, offset: 47694}, + pos: position{line: 1260, col: 128, offset: 47712}, name: "EOL", }, }, @@ -10057,17 +10061,17 @@ var g = &grammar{ }, { name: "ExampleBlockDelimiter", - pos: position{line: 1266, col: 1, offset: 48020}, + pos: position{line: 1267, col: 1, offset: 48038}, expr: &seqExpr{ - pos: position{line: 1266, col: 26, offset: 48045}, + pos: position{line: 1267, col: 26, offset: 48063}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1266, col: 26, offset: 48045}, + pos: position{line: 1267, col: 26, offset: 48063}, val: "====", ignoreCase: false, }, &ruleRefExpr{ - pos: position{line: 1266, col: 33, offset: 48052}, + pos: position{line: 1267, col: 33, offset: 48070}, name: "EOLS", }, }, @@ -10075,50 +10079,50 @@ var g = &grammar{ }, { name: "ExampleBlock", - pos: position{line: 1268, col: 1, offset: 48058}, + pos: position{line: 1269, col: 1, offset: 48076}, expr: &actionExpr{ - pos: position{line: 1268, col: 17, offset: 48074}, + pos: position{line: 1269, col: 17, offset: 48092}, run: (*parser).callonExampleBlock1, expr: &seqExpr{ - pos: position{line: 1268, col: 17, offset: 48074}, + pos: position{line: 1269, col: 17, offset: 48092}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1268, col: 17, offset: 48074}, + pos: position{line: 1269, col: 17, offset: 48092}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 1268, col: 28, offset: 48085}, + pos: position{line: 1269, col: 28, offset: 48103}, expr: &ruleRefExpr{ - pos: position{line: 1268, col: 29, offset: 48086}, + pos: position{line: 1269, col: 29, offset: 48104}, name: "ElementAttributes", }, }, }, &ruleRefExpr{ - pos: position{line: 1268, col: 49, offset: 48106}, + pos: position{line: 1269, col: 49, offset: 48124}, name: "ExampleBlockDelimiter", }, &labeledExpr{ - pos: position{line: 1268, col: 71, offset: 48128}, + pos: position{line: 1269, col: 71, offset: 48146}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 1268, col: 79, offset: 48136}, + pos: position{line: 1269, col: 79, offset: 48154}, expr: &choiceExpr{ - pos: position{line: 1268, col: 80, offset: 48137}, + pos: position{line: 1269, col: 80, offset: 48155}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1268, col: 80, offset: 48137}, + pos: position{line: 1269, col: 80, offset: 48155}, name: "BlankLine", }, &ruleRefExpr{ - pos: position{line: 1268, col: 92, offset: 48149}, + pos: position{line: 1269, col: 92, offset: 48167}, name: "FileInclusion", }, &ruleRefExpr{ - pos: position{line: 1268, col: 108, offset: 48165}, + pos: position{line: 1269, col: 108, offset: 48183}, name: "ListItem", }, &ruleRefExpr{ - pos: position{line: 1268, col: 119, offset: 48176}, + pos: position{line: 1269, col: 119, offset: 48194}, name: "ExampleBlockParagraph", }, }, @@ -10126,14 +10130,14 @@ var g = &grammar{ }, }, &choiceExpr{ - pos: position{line: 1268, col: 145, offset: 48202}, + pos: position{line: 1269, col: 145, offset: 48220}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1268, col: 145, offset: 48202}, + pos: position{line: 1269, col: 145, offset: 48220}, name: "ExampleBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1268, col: 169, offset: 48226}, + pos: position{line: 1269, col: 169, offset: 48244}, name: "EOF", }, }, @@ -10144,17 +10148,17 @@ var g = &grammar{ }, { name: "ExampleBlockParagraph", - pos: position{line: 1273, col: 1, offset: 48353}, + pos: position{line: 1274, col: 1, offset: 48371}, expr: &actionExpr{ - pos: position{line: 1273, col: 26, offset: 48378}, + pos: position{line: 1274, col: 26, offset: 48396}, run: (*parser).callonExampleBlockParagraph1, expr: &labeledExpr{ - pos: position{line: 1273, col: 26, offset: 48378}, + pos: position{line: 1274, col: 26, offset: 48396}, label: "lines", expr: &oneOrMoreExpr{ - pos: position{line: 1273, col: 32, offset: 48384}, + pos: position{line: 1274, col: 32, offset: 48402}, expr: &ruleRefExpr{ - pos: position{line: 1273, col: 33, offset: 48385}, + pos: position{line: 1274, col: 33, offset: 48403}, name: "ExampleBlockParagraphLine", }, }, @@ -10163,32 +10167,32 @@ var g = &grammar{ }, { name: "ExampleBlockParagraphLine", - pos: position{line: 1277, col: 1, offset: 48499}, + pos: position{line: 1278, col: 1, offset: 48517}, expr: &actionExpr{ - pos: position{line: 1277, col: 30, offset: 48528}, + pos: position{line: 1278, col: 30, offset: 48546}, run: (*parser).callonExampleBlockParagraphLine1, expr: &seqExpr{ - pos: position{line: 1277, col: 30, offset: 48528}, + pos: position{line: 1278, col: 30, offset: 48546}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1277, col: 30, offset: 48528}, + pos: position{line: 1278, col: 30, offset: 48546}, expr: &ruleRefExpr{ - pos: position{line: 1277, col: 31, offset: 48529}, + pos: position{line: 1278, col: 31, offset: 48547}, name: "ExampleBlockDelimiter", }, }, ¬Expr{ - pos: position{line: 1277, col: 53, offset: 48551}, + pos: position{line: 1278, col: 53, offset: 48569}, expr: &ruleRefExpr{ - pos: position{line: 1277, col: 54, offset: 48552}, + pos: position{line: 1278, col: 54, offset: 48570}, name: "BlankLine", }, }, &labeledExpr{ - pos: position{line: 1277, col: 64, offset: 48562}, + pos: position{line: 1278, col: 64, offset: 48580}, label: "line", expr: &ruleRefExpr{ - pos: position{line: 1277, col: 70, offset: 48568}, + pos: position{line: 1278, col: 70, offset: 48586}, name: "InlineElements", }, }, @@ -10198,17 +10202,17 @@ var g = &grammar{ }, { name: "QuoteBlockDelimiter", - pos: position{line: 1284, col: 1, offset: 48804}, + pos: position{line: 1285, col: 1, offset: 48822}, expr: &seqExpr{ - pos: position{line: 1284, col: 24, offset: 48827}, + pos: position{line: 1285, col: 24, offset: 48845}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1284, col: 24, offset: 48827}, + pos: position{line: 1285, col: 24, offset: 48845}, val: "____", ignoreCase: false, }, &ruleRefExpr{ - pos: position{line: 1284, col: 31, offset: 48834}, + pos: position{line: 1285, col: 31, offset: 48852}, name: "EOLS", }, }, @@ -10216,48 +10220,48 @@ var g = &grammar{ }, { name: "QuoteBlock", - pos: position{line: 1286, col: 1, offset: 48865}, + pos: position{line: 1287, col: 1, offset: 48883}, expr: &actionExpr{ - pos: position{line: 1286, col: 15, offset: 48879}, + pos: position{line: 1287, col: 15, offset: 48897}, run: (*parser).callonQuoteBlock1, expr: &seqExpr{ - pos: position{line: 1286, col: 15, offset: 48879}, + pos: position{line: 1287, col: 15, offset: 48897}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1286, col: 15, offset: 48879}, + pos: position{line: 1287, col: 15, offset: 48897}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 1286, col: 26, offset: 48890}, + pos: position{line: 1287, col: 26, offset: 48908}, expr: &ruleRefExpr{ - pos: position{line: 1286, col: 27, offset: 48891}, + pos: position{line: 1287, col: 27, offset: 48909}, name: "ElementAttributes", }, }, }, &ruleRefExpr{ - pos: position{line: 1286, col: 47, offset: 48911}, + pos: position{line: 1287, col: 47, offset: 48929}, name: "QuoteBlockDelimiter", }, &labeledExpr{ - pos: position{line: 1286, col: 67, offset: 48931}, + pos: position{line: 1287, col: 67, offset: 48949}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 1286, col: 75, offset: 48939}, + pos: position{line: 1287, col: 75, offset: 48957}, expr: &ruleRefExpr{ - pos: position{line: 1286, col: 76, offset: 48940}, + pos: position{line: 1287, col: 76, offset: 48958}, name: "QuoteBlockElement", }, }, }, &choiceExpr{ - pos: position{line: 1286, col: 97, offset: 48961}, + pos: position{line: 1287, col: 97, offset: 48979}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1286, col: 97, offset: 48961}, + pos: position{line: 1287, col: 97, offset: 48979}, name: "QuoteBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1286, col: 119, offset: 48983}, + pos: position{line: 1287, col: 119, offset: 49001}, name: "EOF", }, }, @@ -10268,99 +10272,99 @@ var g = &grammar{ }, { name: "QuoteBlockElement", - pos: position{line: 1290, col: 1, offset: 49090}, + pos: position{line: 1291, col: 1, offset: 49108}, expr: &actionExpr{ - pos: position{line: 1291, col: 5, offset: 49116}, + pos: position{line: 1292, col: 5, offset: 49134}, run: (*parser).callonQuoteBlockElement1, expr: &seqExpr{ - pos: position{line: 1291, col: 5, offset: 49116}, + pos: position{line: 1292, col: 5, offset: 49134}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1291, col: 5, offset: 49116}, + pos: position{line: 1292, col: 5, offset: 49134}, expr: &ruleRefExpr{ - pos: position{line: 1291, col: 6, offset: 49117}, + pos: position{line: 1292, col: 6, offset: 49135}, name: "QuoteBlockDelimiter", }, }, ¬Expr{ - pos: position{line: 1291, col: 26, offset: 49137}, + pos: position{line: 1292, col: 26, offset: 49155}, expr: &ruleRefExpr{ - pos: position{line: 1291, col: 27, offset: 49138}, + pos: position{line: 1292, col: 27, offset: 49156}, name: "EOF", }, }, &labeledExpr{ - pos: position{line: 1291, col: 31, offset: 49142}, + pos: position{line: 1292, col: 31, offset: 49160}, label: "element", expr: &choiceExpr{ - pos: position{line: 1291, col: 40, offset: 49151}, + pos: position{line: 1292, col: 40, offset: 49169}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1291, col: 40, offset: 49151}, + pos: position{line: 1292, col: 40, offset: 49169}, name: "BlankLine", }, &ruleRefExpr{ - pos: position{line: 1292, col: 15, offset: 49176}, + pos: position{line: 1293, col: 15, offset: 49194}, name: "FileInclusion", }, &ruleRefExpr{ - pos: position{line: 1293, col: 15, offset: 49204}, + pos: position{line: 1294, col: 15, offset: 49222}, name: "ImageBlock", }, &ruleRefExpr{ - pos: position{line: 1294, col: 15, offset: 49230}, + pos: position{line: 1295, col: 15, offset: 49248}, name: "ListItem", }, &ruleRefExpr{ - pos: position{line: 1295, col: 15, offset: 49253}, + pos: position{line: 1296, col: 15, offset: 49271}, name: "FencedBlock", }, &ruleRefExpr{ - pos: position{line: 1296, col: 15, offset: 49279}, + pos: position{line: 1297, col: 15, offset: 49297}, name: "ListingBlock", }, &ruleRefExpr{ - pos: position{line: 1297, col: 15, offset: 49306}, + pos: position{line: 1298, col: 15, offset: 49324}, name: "ExampleBlock", }, &ruleRefExpr{ - pos: position{line: 1298, col: 15, offset: 49333}, + pos: position{line: 1299, col: 15, offset: 49351}, name: "CommentBlock", }, &ruleRefExpr{ - pos: position{line: 1299, col: 15, offset: 49360}, + pos: position{line: 1300, col: 15, offset: 49378}, name: "SingleLineComment", }, &ruleRefExpr{ - pos: position{line: 1300, col: 15, offset: 49392}, + pos: position{line: 1301, col: 15, offset: 49410}, name: "QuoteBlock", }, &ruleRefExpr{ - pos: position{line: 1301, col: 15, offset: 49418}, + pos: position{line: 1302, col: 15, offset: 49436}, name: "SidebarBlock", }, &ruleRefExpr{ - pos: position{line: 1302, col: 15, offset: 49445}, + pos: position{line: 1303, col: 15, offset: 49463}, name: "Table", }, &ruleRefExpr{ - pos: position{line: 1303, col: 15, offset: 49466}, + pos: position{line: 1304, col: 15, offset: 49484}, name: "LiteralBlock", }, &ruleRefExpr{ - pos: position{line: 1304, col: 15, offset: 49494}, + pos: position{line: 1305, col: 15, offset: 49512}, name: "DocumentAttributeDeclaration", }, &ruleRefExpr{ - pos: position{line: 1305, col: 15, offset: 49538}, + pos: position{line: 1306, col: 15, offset: 49556}, name: "DocumentAttributeReset", }, &ruleRefExpr{ - pos: position{line: 1306, col: 15, offset: 49576}, + pos: position{line: 1307, col: 15, offset: 49594}, name: "TableOfContentsMacro", }, &ruleRefExpr{ - pos: position{line: 1307, col: 15, offset: 49611}, + pos: position{line: 1308, col: 15, offset: 49629}, name: "QuoteBlockParagraph", }, }, @@ -10372,17 +10376,17 @@ var g = &grammar{ }, { name: "QuoteBlockParagraph", - pos: position{line: 1311, col: 1, offset: 49670}, + pos: position{line: 1312, col: 1, offset: 49688}, expr: &actionExpr{ - pos: position{line: 1311, col: 24, offset: 49693}, + pos: position{line: 1312, col: 24, offset: 49711}, run: (*parser).callonQuoteBlockParagraph1, expr: &labeledExpr{ - pos: position{line: 1311, col: 24, offset: 49693}, + pos: position{line: 1312, col: 24, offset: 49711}, label: "lines", expr: &oneOrMoreExpr{ - pos: position{line: 1311, col: 30, offset: 49699}, + pos: position{line: 1312, col: 30, offset: 49717}, expr: &ruleRefExpr{ - pos: position{line: 1311, col: 31, offset: 49700}, + pos: position{line: 1312, col: 31, offset: 49718}, name: "InlineElements", }, }, @@ -10391,49 +10395,49 @@ var g = &grammar{ }, { name: "VerseBlock", - pos: position{line: 1320, col: 1, offset: 50046}, + pos: position{line: 1321, col: 1, offset: 50064}, expr: &actionExpr{ - pos: position{line: 1320, col: 15, offset: 50060}, + pos: position{line: 1321, col: 15, offset: 50078}, run: (*parser).callonVerseBlock1, expr: &seqExpr{ - pos: position{line: 1320, col: 15, offset: 50060}, + pos: position{line: 1321, col: 15, offset: 50078}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1320, col: 15, offset: 50060}, + pos: position{line: 1321, col: 15, offset: 50078}, label: "attributes", expr: &ruleRefExpr{ - pos: position{line: 1320, col: 27, offset: 50072}, + pos: position{line: 1321, col: 27, offset: 50090}, name: "ElementAttributes", }, }, &andCodeExpr{ - pos: position{line: 1321, col: 5, offset: 50096}, + pos: position{line: 1322, col: 5, offset: 50114}, run: (*parser).callonVerseBlock5, }, &ruleRefExpr{ - pos: position{line: 1325, col: 5, offset: 50282}, + pos: position{line: 1326, col: 5, offset: 50300}, name: "QuoteBlockDelimiter", }, &labeledExpr{ - pos: position{line: 1325, col: 25, offset: 50302}, + pos: position{line: 1326, col: 25, offset: 50320}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 1325, col: 33, offset: 50310}, + pos: position{line: 1326, col: 33, offset: 50328}, expr: &ruleRefExpr{ - pos: position{line: 1325, col: 34, offset: 50311}, + pos: position{line: 1326, col: 34, offset: 50329}, name: "VerseBlockElement", }, }, }, &choiceExpr{ - pos: position{line: 1325, col: 55, offset: 50332}, + pos: position{line: 1326, col: 55, offset: 50350}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1325, col: 55, offset: 50332}, + pos: position{line: 1326, col: 55, offset: 50350}, name: "QuoteBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1325, col: 77, offset: 50354}, + pos: position{line: 1326, col: 77, offset: 50372}, name: "EOF", }, }, @@ -10444,20 +10448,20 @@ var g = &grammar{ }, { name: "VerseBlockElement", - pos: position{line: 1329, col: 1, offset: 50469}, + pos: position{line: 1330, col: 1, offset: 50487}, expr: &choiceExpr{ - pos: position{line: 1329, col: 22, offset: 50490}, + pos: position{line: 1330, col: 22, offset: 50508}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1329, col: 22, offset: 50490}, + pos: position{line: 1330, col: 22, offset: 50508}, name: "VerseFileInclude", }, &ruleRefExpr{ - pos: position{line: 1329, col: 41, offset: 50509}, + pos: position{line: 1330, col: 41, offset: 50527}, name: "BlankLine", }, &ruleRefExpr{ - pos: position{line: 1329, col: 53, offset: 50521}, + pos: position{line: 1330, col: 53, offset: 50539}, name: "VerseBlockParagraph", }, }, @@ -10465,25 +10469,25 @@ var g = &grammar{ }, { name: "VerseFileInclude", - pos: position{line: 1331, col: 1, offset: 50542}, + pos: position{line: 1332, col: 1, offset: 50560}, expr: &actionExpr{ - pos: position{line: 1331, col: 21, offset: 50562}, + pos: position{line: 1332, col: 21, offset: 50580}, run: (*parser).callonVerseFileInclude1, expr: &seqExpr{ - pos: position{line: 1331, col: 21, offset: 50562}, + pos: position{line: 1332, col: 21, offset: 50580}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1331, col: 21, offset: 50562}, + pos: position{line: 1332, col: 21, offset: 50580}, expr: &ruleRefExpr{ - pos: position{line: 1331, col: 22, offset: 50563}, + pos: position{line: 1332, col: 22, offset: 50581}, name: "QuoteBlockDelimiter", }, }, &labeledExpr{ - pos: position{line: 1331, col: 42, offset: 50583}, + pos: position{line: 1332, col: 42, offset: 50601}, label: "include", expr: &ruleRefExpr{ - pos: position{line: 1331, col: 51, offset: 50592}, + pos: position{line: 1332, col: 51, offset: 50610}, name: "FileInclusion", }, }, @@ -10493,17 +10497,17 @@ var g = &grammar{ }, { name: "VerseBlockParagraph", - pos: position{line: 1336, col: 1, offset: 50654}, + pos: position{line: 1337, col: 1, offset: 50672}, expr: &actionExpr{ - pos: position{line: 1336, col: 24, offset: 50677}, + pos: position{line: 1337, col: 24, offset: 50695}, run: (*parser).callonVerseBlockParagraph1, expr: &labeledExpr{ - pos: position{line: 1336, col: 24, offset: 50677}, + pos: position{line: 1337, col: 24, offset: 50695}, label: "lines", expr: &oneOrMoreExpr{ - pos: position{line: 1336, col: 30, offset: 50683}, + pos: position{line: 1337, col: 30, offset: 50701}, expr: &ruleRefExpr{ - pos: position{line: 1336, col: 31, offset: 50684}, + pos: position{line: 1337, col: 31, offset: 50702}, name: "VerseBlockParagraphLine", }, }, @@ -10512,49 +10516,49 @@ var g = &grammar{ }, { name: "VerseBlockParagraphLine", - pos: position{line: 1340, col: 1, offset: 50774}, + pos: position{line: 1341, col: 1, offset: 50792}, expr: &actionExpr{ - pos: position{line: 1340, col: 28, offset: 50801}, + pos: position{line: 1341, col: 28, offset: 50819}, run: (*parser).callonVerseBlockParagraphLine1, expr: &seqExpr{ - pos: position{line: 1340, col: 28, offset: 50801}, + pos: position{line: 1341, col: 28, offset: 50819}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1340, col: 28, offset: 50801}, + pos: position{line: 1341, col: 28, offset: 50819}, expr: &ruleRefExpr{ - pos: position{line: 1340, col: 29, offset: 50802}, + pos: position{line: 1341, col: 29, offset: 50820}, name: "QuoteBlockDelimiter", }, }, ¬Expr{ - pos: position{line: 1340, col: 49, offset: 50822}, + pos: position{line: 1341, col: 49, offset: 50840}, expr: &ruleRefExpr{ - pos: position{line: 1340, col: 50, offset: 50823}, + pos: position{line: 1341, col: 50, offset: 50841}, name: "BlankLine", }, }, &labeledExpr{ - pos: position{line: 1340, col: 60, offset: 50833}, + pos: position{line: 1341, col: 60, offset: 50851}, label: "line", expr: &actionExpr{ - pos: position{line: 1340, col: 66, offset: 50839}, + pos: position{line: 1341, col: 66, offset: 50857}, run: (*parser).callonVerseBlockParagraphLine8, expr: &seqExpr{ - pos: position{line: 1340, col: 66, offset: 50839}, + pos: position{line: 1341, col: 66, offset: 50857}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1340, col: 66, offset: 50839}, + pos: position{line: 1341, col: 66, offset: 50857}, label: "elements", expr: &oneOrMoreExpr{ - pos: position{line: 1340, col: 75, offset: 50848}, + pos: position{line: 1341, col: 75, offset: 50866}, expr: &ruleRefExpr{ - pos: position{line: 1340, col: 76, offset: 50849}, + pos: position{line: 1341, col: 76, offset: 50867}, name: "VerseBlockParagraphLineElement", }, }, }, &ruleRefExpr{ - pos: position{line: 1340, col: 109, offset: 50882}, + pos: position{line: 1341, col: 109, offset: 50900}, name: "EOL", }, }, @@ -10567,79 +10571,79 @@ var g = &grammar{ }, { name: "VerseBlockParagraphLineElement", - pos: position{line: 1346, col: 1, offset: 50978}, + pos: position{line: 1347, col: 1, offset: 50996}, expr: &actionExpr{ - pos: position{line: 1346, col: 35, offset: 51012}, + pos: position{line: 1347, col: 35, offset: 51030}, run: (*parser).callonVerseBlockParagraphLineElement1, expr: &seqExpr{ - pos: position{line: 1346, col: 35, offset: 51012}, + pos: position{line: 1347, col: 35, offset: 51030}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1346, col: 35, offset: 51012}, + pos: position{line: 1347, col: 35, offset: 51030}, expr: &ruleRefExpr{ - pos: position{line: 1346, col: 36, offset: 51013}, + pos: position{line: 1347, col: 36, offset: 51031}, name: "EOL", }, }, ¬Expr{ - pos: position{line: 1346, col: 40, offset: 51017}, + pos: position{line: 1347, col: 40, offset: 51035}, expr: &ruleRefExpr{ - pos: position{line: 1346, col: 41, offset: 51018}, + pos: position{line: 1347, col: 41, offset: 51036}, name: "LineBreak", }, }, &labeledExpr{ - pos: position{line: 1347, col: 5, offset: 51033}, + pos: position{line: 1348, col: 5, offset: 51051}, label: "element", expr: &choiceExpr{ - pos: position{line: 1347, col: 14, offset: 51042}, + pos: position{line: 1348, col: 14, offset: 51060}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1347, col: 14, offset: 51042}, + pos: position{line: 1348, col: 14, offset: 51060}, name: "Spaces", }, &ruleRefExpr{ - pos: position{line: 1348, col: 11, offset: 51060}, + pos: position{line: 1349, col: 11, offset: 51078}, name: "InlineImage", }, &ruleRefExpr{ - pos: position{line: 1349, col: 11, offset: 51083}, + pos: position{line: 1350, col: 11, offset: 51101}, name: "Link", }, &ruleRefExpr{ - pos: position{line: 1350, col: 11, offset: 51099}, + pos: position{line: 1351, col: 11, offset: 51117}, name: "Passthrough", }, &ruleRefExpr{ - pos: position{line: 1351, col: 11, offset: 51122}, + pos: position{line: 1352, col: 11, offset: 51140}, name: "InlineFootnote", }, &ruleRefExpr{ - pos: position{line: 1352, col: 11, offset: 51148}, + pos: position{line: 1353, col: 11, offset: 51166}, name: "InlineUserMacro", }, &ruleRefExpr{ - pos: position{line: 1353, col: 11, offset: 51175}, + pos: position{line: 1354, col: 11, offset: 51193}, name: "QuotedText", }, &ruleRefExpr{ - pos: position{line: 1354, col: 11, offset: 51197}, + pos: position{line: 1355, col: 11, offset: 51215}, name: "CrossReference", }, &ruleRefExpr{ - pos: position{line: 1355, col: 11, offset: 51223}, + pos: position{line: 1356, col: 11, offset: 51241}, name: "DocumentAttributeSubstitution", }, &ruleRefExpr{ - pos: position{line: 1356, col: 11, offset: 51264}, + pos: position{line: 1357, col: 11, offset: 51282}, name: "InlineElementID", }, &ruleRefExpr{ - pos: position{line: 1357, col: 11, offset: 51291}, + pos: position{line: 1358, col: 11, offset: 51309}, name: "OtherWord", }, &ruleRefExpr{ - pos: position{line: 1358, col: 11, offset: 51311}, + pos: position{line: 1359, col: 11, offset: 51329}, name: "Parenthesis", }, }, @@ -10651,17 +10655,17 @@ var g = &grammar{ }, { name: "SidebarBlockDelimiter", - pos: position{line: 1365, col: 1, offset: 51543}, + pos: position{line: 1366, col: 1, offset: 51561}, expr: &seqExpr{ - pos: position{line: 1365, col: 26, offset: 51568}, + pos: position{line: 1366, col: 26, offset: 51586}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1365, col: 26, offset: 51568}, + pos: position{line: 1366, col: 26, offset: 51586}, val: "****", ignoreCase: false, }, &ruleRefExpr{ - pos: position{line: 1365, col: 33, offset: 51575}, + pos: position{line: 1366, col: 33, offset: 51593}, name: "EOLS", }, }, @@ -10669,48 +10673,48 @@ var g = &grammar{ }, { name: "SidebarBlock", - pos: position{line: 1367, col: 1, offset: 51581}, + pos: position{line: 1368, col: 1, offset: 51599}, expr: &actionExpr{ - pos: position{line: 1367, col: 17, offset: 51597}, + pos: position{line: 1368, col: 17, offset: 51615}, run: (*parser).callonSidebarBlock1, expr: &seqExpr{ - pos: position{line: 1367, col: 17, offset: 51597}, + pos: position{line: 1368, col: 17, offset: 51615}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1367, col: 17, offset: 51597}, + pos: position{line: 1368, col: 17, offset: 51615}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 1367, col: 28, offset: 51608}, + pos: position{line: 1368, col: 28, offset: 51626}, expr: &ruleRefExpr{ - pos: position{line: 1367, col: 29, offset: 51609}, + pos: position{line: 1368, col: 29, offset: 51627}, name: "ElementAttributes", }, }, }, &ruleRefExpr{ - pos: position{line: 1367, col: 49, offset: 51629}, + pos: position{line: 1368, col: 49, offset: 51647}, name: "SidebarBlockDelimiter", }, &labeledExpr{ - pos: position{line: 1367, col: 71, offset: 51651}, + pos: position{line: 1368, col: 71, offset: 51669}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 1367, col: 79, offset: 51659}, + pos: position{line: 1368, col: 79, offset: 51677}, expr: &ruleRefExpr{ - pos: position{line: 1367, col: 80, offset: 51660}, + pos: position{line: 1368, col: 80, offset: 51678}, name: "SidebarBlockContent", }, }, }, &choiceExpr{ - pos: position{line: 1367, col: 104, offset: 51684}, + pos: position{line: 1368, col: 104, offset: 51702}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1367, col: 104, offset: 51684}, + pos: position{line: 1368, col: 104, offset: 51702}, name: "SidebarBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1367, col: 128, offset: 51708}, + pos: position{line: 1368, col: 128, offset: 51726}, name: "EOF", }, }, @@ -10721,28 +10725,28 @@ var g = &grammar{ }, { name: "SidebarBlockContent", - pos: position{line: 1371, col: 1, offset: 51817}, + pos: position{line: 1372, col: 1, offset: 51835}, expr: &choiceExpr{ - pos: position{line: 1371, col: 24, offset: 51840}, + pos: position{line: 1372, col: 24, offset: 51858}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1371, col: 24, offset: 51840}, + pos: position{line: 1372, col: 24, offset: 51858}, name: "BlankLine", }, &ruleRefExpr{ - pos: position{line: 1371, col: 36, offset: 51852}, + pos: position{line: 1372, col: 36, offset: 51870}, name: "FileInclusion", }, &ruleRefExpr{ - pos: position{line: 1371, col: 52, offset: 51868}, + pos: position{line: 1372, col: 52, offset: 51886}, name: "ListItem", }, &ruleRefExpr{ - pos: position{line: 1371, col: 63, offset: 51879}, + pos: position{line: 1372, col: 63, offset: 51897}, name: "NonSidebarBlock", }, &ruleRefExpr{ - pos: position{line: 1371, col: 81, offset: 51897}, + pos: position{line: 1372, col: 81, offset: 51915}, name: "SidebarBlockParagraph", }, }, @@ -10750,25 +10754,25 @@ var g = &grammar{ }, { name: "NonSidebarBlock", - pos: position{line: 1373, col: 1, offset: 51920}, + pos: position{line: 1374, col: 1, offset: 51938}, expr: &actionExpr{ - pos: position{line: 1373, col: 20, offset: 51939}, + pos: position{line: 1374, col: 20, offset: 51957}, run: (*parser).callonNonSidebarBlock1, expr: &seqExpr{ - pos: position{line: 1373, col: 20, offset: 51939}, + pos: position{line: 1374, col: 20, offset: 51957}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1373, col: 20, offset: 51939}, + pos: position{line: 1374, col: 20, offset: 51957}, expr: &ruleRefExpr{ - pos: position{line: 1373, col: 21, offset: 51940}, + pos: position{line: 1374, col: 21, offset: 51958}, name: "SidebarBlock", }, }, &labeledExpr{ - pos: position{line: 1373, col: 34, offset: 51953}, + pos: position{line: 1374, col: 34, offset: 51971}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 1373, col: 43, offset: 51962}, + pos: position{line: 1374, col: 43, offset: 51980}, name: "DelimitedBlock", }, }, @@ -10778,17 +10782,17 @@ var g = &grammar{ }, { name: "SidebarBlockParagraph", - pos: position{line: 1378, col: 1, offset: 52025}, + pos: position{line: 1379, col: 1, offset: 52043}, expr: &actionExpr{ - pos: position{line: 1378, col: 26, offset: 52050}, + pos: position{line: 1379, col: 26, offset: 52068}, run: (*parser).callonSidebarBlockParagraph1, expr: &labeledExpr{ - pos: position{line: 1378, col: 26, offset: 52050}, + pos: position{line: 1379, col: 26, offset: 52068}, label: "lines", expr: &oneOrMoreExpr{ - pos: position{line: 1378, col: 32, offset: 52056}, + pos: position{line: 1379, col: 32, offset: 52074}, expr: &ruleRefExpr{ - pos: position{line: 1378, col: 33, offset: 52057}, + pos: position{line: 1379, col: 33, offset: 52075}, name: "SidebarBlockParagraphLine", }, }, @@ -10797,32 +10801,32 @@ var g = &grammar{ }, { name: "SidebarBlockParagraphLine", - pos: position{line: 1382, col: 1, offset: 52171}, + pos: position{line: 1383, col: 1, offset: 52189}, expr: &actionExpr{ - pos: position{line: 1382, col: 30, offset: 52200}, + pos: position{line: 1383, col: 30, offset: 52218}, run: (*parser).callonSidebarBlockParagraphLine1, expr: &seqExpr{ - pos: position{line: 1382, col: 30, offset: 52200}, + pos: position{line: 1383, col: 30, offset: 52218}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1382, col: 30, offset: 52200}, + pos: position{line: 1383, col: 30, offset: 52218}, expr: &ruleRefExpr{ - pos: position{line: 1382, col: 31, offset: 52201}, + pos: position{line: 1383, col: 31, offset: 52219}, name: "SidebarBlockDelimiter", }, }, ¬Expr{ - pos: position{line: 1382, col: 53, offset: 52223}, + pos: position{line: 1383, col: 53, offset: 52241}, expr: &ruleRefExpr{ - pos: position{line: 1382, col: 54, offset: 52224}, + pos: position{line: 1383, col: 54, offset: 52242}, name: "BlankLine", }, }, &labeledExpr{ - pos: position{line: 1382, col: 64, offset: 52234}, + pos: position{line: 1383, col: 64, offset: 52252}, label: "line", expr: &ruleRefExpr{ - pos: position{line: 1382, col: 70, offset: 52240}, + pos: position{line: 1383, col: 70, offset: 52258}, name: "InlineElements", }, }, @@ -10832,59 +10836,59 @@ var g = &grammar{ }, { name: "Table", - pos: position{line: 1390, col: 1, offset: 52471}, + pos: position{line: 1391, col: 1, offset: 52489}, expr: &actionExpr{ - pos: position{line: 1390, col: 10, offset: 52480}, + pos: position{line: 1391, col: 10, offset: 52498}, run: (*parser).callonTable1, expr: &seqExpr{ - pos: position{line: 1390, col: 10, offset: 52480}, + pos: position{line: 1391, col: 10, offset: 52498}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1390, col: 10, offset: 52480}, + pos: position{line: 1391, col: 10, offset: 52498}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 1390, col: 21, offset: 52491}, + pos: position{line: 1391, col: 21, offset: 52509}, expr: &ruleRefExpr{ - pos: position{line: 1390, col: 22, offset: 52492}, + pos: position{line: 1391, col: 22, offset: 52510}, name: "ElementAttributes", }, }, }, &ruleRefExpr{ - pos: position{line: 1390, col: 42, offset: 52512}, + pos: position{line: 1391, col: 42, offset: 52530}, name: "TableDelimiter", }, &labeledExpr{ - pos: position{line: 1391, col: 5, offset: 52531}, + pos: position{line: 1392, col: 5, offset: 52549}, label: "header", expr: &zeroOrOneExpr{ - pos: position{line: 1391, col: 12, offset: 52538}, + pos: position{line: 1392, col: 12, offset: 52556}, expr: &ruleRefExpr{ - pos: position{line: 1391, col: 13, offset: 52539}, + pos: position{line: 1392, col: 13, offset: 52557}, name: "TableLineHeader", }, }, }, &labeledExpr{ - pos: position{line: 1392, col: 5, offset: 52561}, + pos: position{line: 1393, col: 5, offset: 52579}, label: "lines", expr: &zeroOrMoreExpr{ - pos: position{line: 1392, col: 11, offset: 52567}, + pos: position{line: 1393, col: 11, offset: 52585}, expr: &ruleRefExpr{ - pos: position{line: 1392, col: 12, offset: 52568}, + pos: position{line: 1393, col: 12, offset: 52586}, name: "TableLine", }, }, }, &choiceExpr{ - pos: position{line: 1393, col: 6, offset: 52585}, + pos: position{line: 1394, col: 6, offset: 52603}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1393, col: 6, offset: 52585}, + pos: position{line: 1394, col: 6, offset: 52603}, name: "TableDelimiter", }, &ruleRefExpr{ - pos: position{line: 1393, col: 23, offset: 52602}, + pos: position{line: 1394, col: 23, offset: 52620}, name: "EOF", }, }, @@ -10895,19 +10899,19 @@ var g = &grammar{ }, { name: "TableCellSeparator", - pos: position{line: 1397, col: 1, offset: 52717}, + pos: position{line: 1398, col: 1, offset: 52735}, expr: &seqExpr{ - pos: position{line: 1397, col: 23, offset: 52739}, + pos: position{line: 1398, col: 23, offset: 52757}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1397, col: 23, offset: 52739}, + pos: position{line: 1398, col: 23, offset: 52757}, val: "|", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 1397, col: 27, offset: 52743}, + pos: position{line: 1398, col: 27, offset: 52761}, expr: &ruleRefExpr{ - pos: position{line: 1397, col: 27, offset: 52743}, + pos: position{line: 1398, col: 27, offset: 52761}, name: "WS", }, }, @@ -10916,17 +10920,17 @@ var g = &grammar{ }, { name: "TableDelimiter", - pos: position{line: 1399, col: 1, offset: 52748}, + pos: position{line: 1400, col: 1, offset: 52766}, expr: &seqExpr{ - pos: position{line: 1399, col: 19, offset: 52766}, + pos: position{line: 1400, col: 19, offset: 52784}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 1399, col: 19, offset: 52766}, + pos: position{line: 1400, col: 19, offset: 52784}, val: "|===", ignoreCase: false, }, &ruleRefExpr{ - pos: position{line: 1399, col: 26, offset: 52773}, + pos: position{line: 1400, col: 26, offset: 52791}, name: "EOLS", }, }, @@ -10934,37 +10938,37 @@ var g = &grammar{ }, { name: "TableLineHeader", - pos: position{line: 1402, col: 1, offset: 52842}, + pos: position{line: 1403, col: 1, offset: 52860}, expr: &actionExpr{ - pos: position{line: 1402, col: 20, offset: 52861}, + pos: position{line: 1403, col: 20, offset: 52879}, run: (*parser).callonTableLineHeader1, expr: &seqExpr{ - pos: position{line: 1402, col: 20, offset: 52861}, + pos: position{line: 1403, col: 20, offset: 52879}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1402, col: 20, offset: 52861}, + pos: position{line: 1403, col: 20, offset: 52879}, expr: &ruleRefExpr{ - pos: position{line: 1402, col: 21, offset: 52862}, + pos: position{line: 1403, col: 21, offset: 52880}, name: "TableDelimiter", }, }, &labeledExpr{ - pos: position{line: 1402, col: 36, offset: 52877}, + pos: position{line: 1403, col: 36, offset: 52895}, label: "cells", expr: &oneOrMoreExpr{ - pos: position{line: 1402, col: 42, offset: 52883}, + pos: position{line: 1403, col: 42, offset: 52901}, expr: &ruleRefExpr{ - pos: position{line: 1402, col: 43, offset: 52884}, + pos: position{line: 1403, col: 43, offset: 52902}, name: "TableCell", }, }, }, &ruleRefExpr{ - pos: position{line: 1402, col: 55, offset: 52896}, + pos: position{line: 1403, col: 55, offset: 52914}, name: "EOL", }, &ruleRefExpr{ - pos: position{line: 1402, col: 59, offset: 52900}, + pos: position{line: 1403, col: 59, offset: 52918}, name: "BlankLine", }, }, @@ -10973,39 +10977,39 @@ var g = &grammar{ }, { name: "TableLine", - pos: position{line: 1406, col: 1, offset: 52968}, + pos: position{line: 1407, col: 1, offset: 52986}, expr: &actionExpr{ - pos: position{line: 1406, col: 14, offset: 52981}, + pos: position{line: 1407, col: 14, offset: 52999}, run: (*parser).callonTableLine1, expr: &seqExpr{ - pos: position{line: 1406, col: 14, offset: 52981}, + pos: position{line: 1407, col: 14, offset: 52999}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1406, col: 14, offset: 52981}, + pos: position{line: 1407, col: 14, offset: 52999}, expr: &ruleRefExpr{ - pos: position{line: 1406, col: 15, offset: 52982}, + pos: position{line: 1407, col: 15, offset: 53000}, name: "TableDelimiter", }, }, &labeledExpr{ - pos: position{line: 1406, col: 30, offset: 52997}, + pos: position{line: 1407, col: 30, offset: 53015}, label: "cells", expr: &oneOrMoreExpr{ - pos: position{line: 1406, col: 36, offset: 53003}, + pos: position{line: 1407, col: 36, offset: 53021}, expr: &ruleRefExpr{ - pos: position{line: 1406, col: 37, offset: 53004}, + pos: position{line: 1407, col: 37, offset: 53022}, name: "TableCell", }, }, }, &ruleRefExpr{ - pos: position{line: 1406, col: 49, offset: 53016}, + pos: position{line: 1407, col: 49, offset: 53034}, name: "EOL", }, &zeroOrMoreExpr{ - pos: position{line: 1406, col: 53, offset: 53020}, + pos: position{line: 1407, col: 53, offset: 53038}, expr: &ruleRefExpr{ - pos: position{line: 1406, col: 53, offset: 53020}, + pos: position{line: 1407, col: 53, offset: 53038}, name: "BlankLine", }, }, @@ -11015,54 +11019,54 @@ var g = &grammar{ }, { name: "TableCell", - pos: position{line: 1410, col: 1, offset: 53089}, + pos: position{line: 1411, col: 1, offset: 53107}, expr: &actionExpr{ - pos: position{line: 1410, col: 14, offset: 53102}, + pos: position{line: 1411, col: 14, offset: 53120}, run: (*parser).callonTableCell1, expr: &seqExpr{ - pos: position{line: 1410, col: 14, offset: 53102}, + pos: position{line: 1411, col: 14, offset: 53120}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 1410, col: 14, offset: 53102}, + pos: position{line: 1411, col: 14, offset: 53120}, name: "TableCellSeparator", }, &labeledExpr{ - pos: position{line: 1410, col: 33, offset: 53121}, + pos: position{line: 1411, col: 33, offset: 53139}, label: "elements", expr: &oneOrMoreExpr{ - pos: position{line: 1410, col: 42, offset: 53130}, + pos: position{line: 1411, col: 42, offset: 53148}, expr: &seqExpr{ - pos: position{line: 1410, col: 43, offset: 53131}, + pos: position{line: 1411, col: 43, offset: 53149}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1410, col: 43, offset: 53131}, + pos: position{line: 1411, col: 43, offset: 53149}, expr: &ruleRefExpr{ - pos: position{line: 1410, col: 44, offset: 53132}, + pos: position{line: 1411, col: 44, offset: 53150}, name: "TableCellSeparator", }, }, ¬Expr{ - pos: position{line: 1410, col: 63, offset: 53151}, + pos: position{line: 1411, col: 63, offset: 53169}, expr: &ruleRefExpr{ - pos: position{line: 1410, col: 64, offset: 53152}, + pos: position{line: 1411, col: 64, offset: 53170}, name: "EOL", }, }, &zeroOrMoreExpr{ - pos: position{line: 1410, col: 68, offset: 53156}, + pos: position{line: 1411, col: 68, offset: 53174}, expr: &ruleRefExpr{ - pos: position{line: 1410, col: 68, offset: 53156}, + pos: position{line: 1411, col: 68, offset: 53174}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 1410, col: 72, offset: 53160}, + pos: position{line: 1411, col: 72, offset: 53178}, name: "InlineElement", }, &zeroOrMoreExpr{ - pos: position{line: 1410, col: 86, offset: 53174}, + pos: position{line: 1411, col: 86, offset: 53192}, expr: &ruleRefExpr{ - pos: position{line: 1410, col: 86, offset: 53174}, + pos: position{line: 1411, col: 86, offset: 53192}, name: "WS", }, }, @@ -11076,66 +11080,66 @@ var g = &grammar{ }, { name: "CommentBlockDelimiter", - pos: position{line: 1417, col: 1, offset: 53420}, + pos: position{line: 1418, col: 1, offset: 53438}, expr: &litMatcher{ - pos: position{line: 1417, col: 26, offset: 53445}, + pos: position{line: 1418, col: 26, offset: 53463}, val: "////", ignoreCase: false, }, }, { name: "CommentBlock", - pos: position{line: 1419, col: 1, offset: 53453}, + pos: position{line: 1420, col: 1, offset: 53471}, expr: &actionExpr{ - pos: position{line: 1419, col: 17, offset: 53469}, + pos: position{line: 1420, col: 17, offset: 53487}, run: (*parser).callonCommentBlock1, expr: &seqExpr{ - pos: position{line: 1419, col: 17, offset: 53469}, + pos: position{line: 1420, col: 17, offset: 53487}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 1419, col: 17, offset: 53469}, + pos: position{line: 1420, col: 17, offset: 53487}, name: "CommentBlockDelimiter", }, &zeroOrMoreExpr{ - pos: position{line: 1419, col: 39, offset: 53491}, + pos: position{line: 1420, col: 39, offset: 53509}, expr: &ruleRefExpr{ - pos: position{line: 1419, col: 39, offset: 53491}, + pos: position{line: 1420, col: 39, offset: 53509}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 1419, col: 43, offset: 53495}, + pos: position{line: 1420, col: 43, offset: 53513}, name: "NEWLINE", }, &labeledExpr{ - pos: position{line: 1419, col: 51, offset: 53503}, + pos: position{line: 1420, col: 51, offset: 53521}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 1419, col: 59, offset: 53511}, + pos: position{line: 1420, col: 59, offset: 53529}, expr: &ruleRefExpr{ - pos: position{line: 1419, col: 60, offset: 53512}, + pos: position{line: 1420, col: 60, offset: 53530}, name: "CommentBlockLine", }, }, }, &choiceExpr{ - pos: position{line: 1419, col: 81, offset: 53533}, + pos: position{line: 1420, col: 81, offset: 53551}, alternatives: []interface{}{ &seqExpr{ - pos: position{line: 1419, col: 82, offset: 53534}, + pos: position{line: 1420, col: 82, offset: 53552}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 1419, col: 82, offset: 53534}, + pos: position{line: 1420, col: 82, offset: 53552}, name: "CommentBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1419, col: 104, offset: 53556}, + pos: position{line: 1420, col: 104, offset: 53574}, name: "EOLS", }, }, }, &ruleRefExpr{ - pos: position{line: 1419, col: 112, offset: 53564}, + pos: position{line: 1420, col: 112, offset: 53582}, name: "EOF", }, }, @@ -11146,45 +11150,45 @@ var g = &grammar{ }, { name: "CommentBlockLine", - pos: position{line: 1423, col: 1, offset: 53670}, + pos: position{line: 1424, col: 1, offset: 53688}, expr: &actionExpr{ - pos: position{line: 1423, col: 21, offset: 53690}, + pos: position{line: 1424, col: 21, offset: 53708}, run: (*parser).callonCommentBlockLine1, expr: &seqExpr{ - pos: position{line: 1423, col: 21, offset: 53690}, + pos: position{line: 1424, col: 21, offset: 53708}, exprs: []interface{}{ &zeroOrMoreExpr{ - pos: position{line: 1423, col: 21, offset: 53690}, + pos: position{line: 1424, col: 21, offset: 53708}, expr: &choiceExpr{ - pos: position{line: 1423, col: 22, offset: 53691}, + pos: position{line: 1424, col: 22, offset: 53709}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1423, col: 22, offset: 53691}, + pos: position{line: 1424, col: 22, offset: 53709}, name: "Alphanums", }, &ruleRefExpr{ - pos: position{line: 1423, col: 34, offset: 53703}, + pos: position{line: 1424, col: 34, offset: 53721}, name: "Spaces", }, &seqExpr{ - pos: position{line: 1423, col: 44, offset: 53713}, + pos: position{line: 1424, col: 44, offset: 53731}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1423, col: 44, offset: 53713}, + pos: position{line: 1424, col: 44, offset: 53731}, expr: &ruleRefExpr{ - pos: position{line: 1423, col: 45, offset: 53714}, + pos: position{line: 1424, col: 45, offset: 53732}, name: "CommentBlockDelimiter", }, }, ¬Expr{ - pos: position{line: 1423, col: 67, offset: 53736}, + pos: position{line: 1424, col: 67, offset: 53754}, expr: &ruleRefExpr{ - pos: position{line: 1423, col: 68, offset: 53737}, + pos: position{line: 1424, col: 68, offset: 53755}, name: "EOL", }, }, &anyMatcher{ - line: 1423, col: 72, offset: 53741, + line: 1424, col: 72, offset: 53759, }, }, }, @@ -11192,7 +11196,7 @@ var g = &grammar{ }, }, &ruleRefExpr{ - pos: position{line: 1423, col: 77, offset: 53746}, + pos: position{line: 1424, col: 77, offset: 53764}, name: "EOL", }, }, @@ -11201,42 +11205,42 @@ var g = &grammar{ }, { name: "SingleLineComment", - pos: position{line: 1427, col: 1, offset: 53786}, + pos: position{line: 1428, col: 1, offset: 53804}, expr: &actionExpr{ - pos: position{line: 1427, col: 22, offset: 53807}, + pos: position{line: 1428, col: 22, offset: 53825}, run: (*parser).callonSingleLineComment1, expr: &seqExpr{ - pos: position{line: 1427, col: 22, offset: 53807}, + pos: position{line: 1428, col: 22, offset: 53825}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1427, col: 22, offset: 53807}, + pos: position{line: 1428, col: 22, offset: 53825}, expr: &ruleRefExpr{ - pos: position{line: 1427, col: 23, offset: 53808}, + pos: position{line: 1428, col: 23, offset: 53826}, name: "CommentBlockDelimiter", }, }, &zeroOrMoreExpr{ - pos: position{line: 1427, col: 45, offset: 53830}, + pos: position{line: 1428, col: 45, offset: 53848}, expr: &ruleRefExpr{ - pos: position{line: 1427, col: 45, offset: 53830}, + pos: position{line: 1428, col: 45, offset: 53848}, name: "WS", }, }, &litMatcher{ - pos: position{line: 1427, col: 49, offset: 53834}, + pos: position{line: 1428, col: 49, offset: 53852}, val: "//", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 1427, col: 54, offset: 53839}, + pos: position{line: 1428, col: 54, offset: 53857}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 1427, col: 63, offset: 53848}, + pos: position{line: 1428, col: 63, offset: 53866}, name: "SingleLineCommentContent", }, }, &ruleRefExpr{ - pos: position{line: 1427, col: 89, offset: 53874}, + pos: position{line: 1428, col: 89, offset: 53892}, name: "EOL", }, }, @@ -11245,35 +11249,35 @@ var g = &grammar{ }, { name: "SingleLineCommentContent", - pos: position{line: 1431, col: 1, offset: 53939}, + pos: position{line: 1432, col: 1, offset: 53957}, expr: &actionExpr{ - pos: position{line: 1431, col: 29, offset: 53967}, + pos: position{line: 1432, col: 29, offset: 53985}, run: (*parser).callonSingleLineCommentContent1, expr: &zeroOrMoreExpr{ - pos: position{line: 1431, col: 29, offset: 53967}, + pos: position{line: 1432, col: 29, offset: 53985}, expr: &choiceExpr{ - pos: position{line: 1431, col: 30, offset: 53968}, + pos: position{line: 1432, col: 30, offset: 53986}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1431, col: 30, offset: 53968}, + pos: position{line: 1432, col: 30, offset: 53986}, name: "Alphanums", }, &ruleRefExpr{ - pos: position{line: 1431, col: 42, offset: 53980}, + pos: position{line: 1432, col: 42, offset: 53998}, name: "Spaces", }, &seqExpr{ - pos: position{line: 1431, col: 52, offset: 53990}, + pos: position{line: 1432, col: 52, offset: 54008}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1431, col: 52, offset: 53990}, + pos: position{line: 1432, col: 52, offset: 54008}, expr: &ruleRefExpr{ - pos: position{line: 1431, col: 53, offset: 53991}, + pos: position{line: 1432, col: 53, offset: 54009}, name: "EOL", }, }, &anyMatcher{ - line: 1431, col: 58, offset: 53996, + line: 1432, col: 58, offset: 54014, }, }, }, @@ -11284,20 +11288,20 @@ var g = &grammar{ }, { name: "LiteralBlock", - pos: position{line: 1439, col: 1, offset: 54305}, + pos: position{line: 1440, col: 1, offset: 54323}, expr: &choiceExpr{ - pos: position{line: 1439, col: 17, offset: 54321}, + pos: position{line: 1440, col: 17, offset: 54339}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1439, col: 17, offset: 54321}, + pos: position{line: 1440, col: 17, offset: 54339}, name: "ParagraphWithLiteralAttribute", }, &ruleRefExpr{ - pos: position{line: 1439, col: 49, offset: 54353}, + pos: position{line: 1440, col: 49, offset: 54371}, name: "ParagraphWithHeadingSpaces", }, &ruleRefExpr{ - pos: position{line: 1439, col: 78, offset: 54382}, + pos: position{line: 1440, col: 78, offset: 54400}, name: "ParagraphWithLiteralBlockDelimiter", }, }, @@ -11305,38 +11309,38 @@ var g = &grammar{ }, { name: "LiteralBlockDelimiter", - pos: position{line: 1441, col: 1, offset: 54418}, + pos: position{line: 1442, col: 1, offset: 54436}, expr: &litMatcher{ - pos: position{line: 1441, col: 26, offset: 54443}, + pos: position{line: 1442, col: 26, offset: 54461}, val: "....", ignoreCase: false, }, }, { name: "ParagraphWithHeadingSpaces", - pos: position{line: 1444, col: 1, offset: 54515}, + pos: position{line: 1445, col: 1, offset: 54533}, expr: &actionExpr{ - pos: position{line: 1444, col: 31, offset: 54545}, + pos: position{line: 1445, col: 31, offset: 54563}, run: (*parser).callonParagraphWithHeadingSpaces1, expr: &seqExpr{ - pos: position{line: 1444, col: 31, offset: 54545}, + pos: position{line: 1445, col: 31, offset: 54563}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1444, col: 31, offset: 54545}, + pos: position{line: 1445, col: 31, offset: 54563}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 1444, col: 42, offset: 54556}, + pos: position{line: 1445, col: 42, offset: 54574}, expr: &ruleRefExpr{ - pos: position{line: 1444, col: 43, offset: 54557}, + pos: position{line: 1445, col: 43, offset: 54575}, name: "ElementAttributes", }, }, }, &labeledExpr{ - pos: position{line: 1444, col: 63, offset: 54577}, + pos: position{line: 1445, col: 63, offset: 54595}, label: "lines", expr: &ruleRefExpr{ - pos: position{line: 1444, col: 70, offset: 54584}, + pos: position{line: 1445, col: 70, offset: 54602}, name: "ParagraphWithHeadingSpacesLines", }, }, @@ -11346,54 +11350,54 @@ var g = &grammar{ }, { name: "ParagraphWithHeadingSpacesLines", - pos: position{line: 1449, col: 1, offset: 54814}, + pos: position{line: 1450, col: 1, offset: 54832}, expr: &actionExpr{ - pos: position{line: 1450, col: 5, offset: 54854}, + pos: position{line: 1451, col: 5, offset: 54872}, run: (*parser).callonParagraphWithHeadingSpacesLines1, expr: &seqExpr{ - pos: position{line: 1450, col: 5, offset: 54854}, + pos: position{line: 1451, col: 5, offset: 54872}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1450, col: 5, offset: 54854}, + pos: position{line: 1451, col: 5, offset: 54872}, label: "firstLine", expr: &actionExpr{ - pos: position{line: 1450, col: 16, offset: 54865}, + pos: position{line: 1451, col: 16, offset: 54883}, run: (*parser).callonParagraphWithHeadingSpacesLines4, expr: &seqExpr{ - pos: position{line: 1450, col: 16, offset: 54865}, + pos: position{line: 1451, col: 16, offset: 54883}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 1450, col: 16, offset: 54865}, + pos: position{line: 1451, col: 16, offset: 54883}, name: "WS", }, &oneOrMoreExpr{ - pos: position{line: 1450, col: 19, offset: 54868}, + pos: position{line: 1451, col: 19, offset: 54886}, expr: &choiceExpr{ - pos: position{line: 1450, col: 20, offset: 54869}, + pos: position{line: 1451, col: 20, offset: 54887}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1450, col: 20, offset: 54869}, + pos: position{line: 1451, col: 20, offset: 54887}, name: "Alphanums", }, &ruleRefExpr{ - pos: position{line: 1450, col: 32, offset: 54881}, + pos: position{line: 1451, col: 32, offset: 54899}, name: "Spaces", }, &actionExpr{ - pos: position{line: 1450, col: 41, offset: 54890}, + pos: position{line: 1451, col: 41, offset: 54908}, run: (*parser).callonParagraphWithHeadingSpacesLines11, expr: &seqExpr{ - pos: position{line: 1450, col: 42, offset: 54891}, + pos: position{line: 1451, col: 42, offset: 54909}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1450, col: 42, offset: 54891}, + pos: position{line: 1451, col: 42, offset: 54909}, expr: &ruleRefExpr{ - pos: position{line: 1450, col: 43, offset: 54892}, + pos: position{line: 1451, col: 43, offset: 54910}, name: "EOL", }, }, &anyMatcher{ - line: 1450, col: 48, offset: 54897, + line: 1451, col: 48, offset: 54915, }, }, }, @@ -11406,58 +11410,58 @@ var g = &grammar{ }, }, &ruleRefExpr{ - pos: position{line: 1454, col: 8, offset: 54988}, + pos: position{line: 1455, col: 8, offset: 55006}, name: "EOL", }, &labeledExpr{ - pos: position{line: 1455, col: 5, offset: 55051}, + pos: position{line: 1456, col: 5, offset: 55069}, label: "otherLines", expr: &zeroOrMoreExpr{ - pos: position{line: 1455, col: 16, offset: 55062}, + pos: position{line: 1456, col: 16, offset: 55080}, expr: &actionExpr{ - pos: position{line: 1456, col: 9, offset: 55072}, + pos: position{line: 1457, col: 9, offset: 55090}, run: (*parser).callonParagraphWithHeadingSpacesLines19, expr: &seqExpr{ - pos: position{line: 1456, col: 9, offset: 55072}, + pos: position{line: 1457, col: 9, offset: 55090}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1456, col: 9, offset: 55072}, + pos: position{line: 1457, col: 9, offset: 55090}, expr: &ruleRefExpr{ - pos: position{line: 1456, col: 10, offset: 55073}, + pos: position{line: 1457, col: 10, offset: 55091}, name: "BlankLine", }, }, &labeledExpr{ - pos: position{line: 1457, col: 9, offset: 55092}, + pos: position{line: 1458, col: 9, offset: 55110}, label: "otherLine", expr: &actionExpr{ - pos: position{line: 1457, col: 20, offset: 55103}, + pos: position{line: 1458, col: 20, offset: 55121}, run: (*parser).callonParagraphWithHeadingSpacesLines24, expr: &oneOrMoreExpr{ - pos: position{line: 1457, col: 20, offset: 55103}, + pos: position{line: 1458, col: 20, offset: 55121}, expr: &choiceExpr{ - pos: position{line: 1457, col: 21, offset: 55104}, + pos: position{line: 1458, col: 21, offset: 55122}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1457, col: 21, offset: 55104}, + pos: position{line: 1458, col: 21, offset: 55122}, name: "Alphanums", }, &ruleRefExpr{ - pos: position{line: 1457, col: 33, offset: 55116}, + pos: position{line: 1458, col: 33, offset: 55134}, name: "Spaces", }, &seqExpr{ - pos: position{line: 1457, col: 43, offset: 55126}, + pos: position{line: 1458, col: 43, offset: 55144}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1457, col: 43, offset: 55126}, + pos: position{line: 1458, col: 43, offset: 55144}, expr: &ruleRefExpr{ - pos: position{line: 1457, col: 44, offset: 55127}, + pos: position{line: 1458, col: 44, offset: 55145}, name: "EOL", }, }, &anyMatcher{ - line: 1457, col: 49, offset: 55132, + line: 1458, col: 49, offset: 55150, }, }, }, @@ -11467,7 +11471,7 @@ var g = &grammar{ }, }, &ruleRefExpr{ - pos: position{line: 1459, col: 12, offset: 55189}, + pos: position{line: 1460, col: 12, offset: 55207}, name: "EOL", }, }, @@ -11481,65 +11485,65 @@ var g = &grammar{ }, { name: "ParagraphWithLiteralBlockDelimiter", - pos: position{line: 1466, col: 1, offset: 55419}, + pos: position{line: 1467, col: 1, offset: 55437}, expr: &actionExpr{ - pos: position{line: 1466, col: 39, offset: 55457}, + pos: position{line: 1467, col: 39, offset: 55475}, run: (*parser).callonParagraphWithLiteralBlockDelimiter1, expr: &seqExpr{ - pos: position{line: 1466, col: 39, offset: 55457}, + pos: position{line: 1467, col: 39, offset: 55475}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1466, col: 39, offset: 55457}, + pos: position{line: 1467, col: 39, offset: 55475}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 1466, col: 50, offset: 55468}, + pos: position{line: 1467, col: 50, offset: 55486}, expr: &ruleRefExpr{ - pos: position{line: 1466, col: 51, offset: 55469}, + pos: position{line: 1467, col: 51, offset: 55487}, name: "ElementAttributes", }, }, }, &ruleRefExpr{ - pos: position{line: 1467, col: 9, offset: 55497}, + pos: position{line: 1468, col: 9, offset: 55515}, name: "LiteralBlockDelimiter", }, &zeroOrMoreExpr{ - pos: position{line: 1467, col: 31, offset: 55519}, + pos: position{line: 1468, col: 31, offset: 55537}, expr: &ruleRefExpr{ - pos: position{line: 1467, col: 31, offset: 55519}, + pos: position{line: 1468, col: 31, offset: 55537}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 1467, col: 35, offset: 55523}, + pos: position{line: 1468, col: 35, offset: 55541}, name: "NEWLINE", }, &labeledExpr{ - pos: position{line: 1467, col: 43, offset: 55531}, + pos: position{line: 1468, col: 43, offset: 55549}, label: "lines", expr: &ruleRefExpr{ - pos: position{line: 1467, col: 50, offset: 55538}, + pos: position{line: 1468, col: 50, offset: 55556}, name: "ParagraphWithLiteralBlockDelimiterLines", }, }, &choiceExpr{ - pos: position{line: 1467, col: 92, offset: 55580}, + pos: position{line: 1468, col: 92, offset: 55598}, alternatives: []interface{}{ &seqExpr{ - pos: position{line: 1467, col: 93, offset: 55581}, + pos: position{line: 1468, col: 93, offset: 55599}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 1467, col: 93, offset: 55581}, + pos: position{line: 1468, col: 93, offset: 55599}, name: "LiteralBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 1467, col: 115, offset: 55603}, + pos: position{line: 1468, col: 115, offset: 55621}, name: "EOLS", }, }, }, &ruleRefExpr{ - pos: position{line: 1467, col: 123, offset: 55611}, + pos: position{line: 1468, col: 123, offset: 55629}, name: "EOF", }, }, @@ -11550,17 +11554,17 @@ var g = &grammar{ }, { name: "ParagraphWithLiteralBlockDelimiterLines", - pos: position{line: 1472, col: 1, offset: 55770}, + pos: position{line: 1473, col: 1, offset: 55788}, expr: &actionExpr{ - pos: position{line: 1472, col: 44, offset: 55813}, + pos: position{line: 1473, col: 44, offset: 55831}, run: (*parser).callonParagraphWithLiteralBlockDelimiterLines1, expr: &labeledExpr{ - pos: position{line: 1472, col: 44, offset: 55813}, + pos: position{line: 1473, col: 44, offset: 55831}, label: "lines", expr: &zeroOrMoreExpr{ - pos: position{line: 1472, col: 50, offset: 55819}, + pos: position{line: 1473, col: 50, offset: 55837}, expr: &ruleRefExpr{ - pos: position{line: 1472, col: 51, offset: 55820}, + pos: position{line: 1473, col: 51, offset: 55838}, name: "ParagraphWithLiteralBlockDelimiterLine", }, }, @@ -11569,51 +11573,51 @@ var g = &grammar{ }, { name: "ParagraphWithLiteralBlockDelimiterLine", - pos: position{line: 1476, col: 1, offset: 55904}, + pos: position{line: 1477, col: 1, offset: 55922}, expr: &actionExpr{ - pos: position{line: 1477, col: 5, offset: 55959}, + pos: position{line: 1478, col: 5, offset: 55977}, run: (*parser).callonParagraphWithLiteralBlockDelimiterLine1, expr: &seqExpr{ - pos: position{line: 1477, col: 5, offset: 55959}, + pos: position{line: 1478, col: 5, offset: 55977}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1477, col: 5, offset: 55959}, + pos: position{line: 1478, col: 5, offset: 55977}, label: "line", expr: &actionExpr{ - pos: position{line: 1477, col: 11, offset: 55965}, + pos: position{line: 1478, col: 11, offset: 55983}, run: (*parser).callonParagraphWithLiteralBlockDelimiterLine4, expr: &zeroOrMoreExpr{ - pos: position{line: 1477, col: 11, offset: 55965}, + pos: position{line: 1478, col: 11, offset: 55983}, expr: &choiceExpr{ - pos: position{line: 1477, col: 12, offset: 55966}, + pos: position{line: 1478, col: 12, offset: 55984}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1477, col: 12, offset: 55966}, + pos: position{line: 1478, col: 12, offset: 55984}, name: "Alphanums", }, &ruleRefExpr{ - pos: position{line: 1477, col: 24, offset: 55978}, + pos: position{line: 1478, col: 24, offset: 55996}, name: "Spaces", }, &seqExpr{ - pos: position{line: 1477, col: 34, offset: 55988}, + pos: position{line: 1478, col: 34, offset: 56006}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1477, col: 34, offset: 55988}, + pos: position{line: 1478, col: 34, offset: 56006}, expr: &ruleRefExpr{ - pos: position{line: 1477, col: 35, offset: 55989}, + pos: position{line: 1478, col: 35, offset: 56007}, name: "LiteralBlockDelimiter", }, }, ¬Expr{ - pos: position{line: 1477, col: 57, offset: 56011}, + pos: position{line: 1478, col: 57, offset: 56029}, expr: &ruleRefExpr{ - pos: position{line: 1477, col: 58, offset: 56012}, + pos: position{line: 1478, col: 58, offset: 56030}, name: "EOL", }, }, &anyMatcher{ - line: 1477, col: 62, offset: 56016, + line: 1478, col: 62, offset: 56034, }, }, }, @@ -11623,7 +11627,7 @@ var g = &grammar{ }, }, &ruleRefExpr{ - pos: position{line: 1479, col: 8, offset: 56065}, + pos: position{line: 1480, col: 8, offset: 56083}, name: "EOL", }, }, @@ -11632,33 +11636,33 @@ var g = &grammar{ }, { name: "ParagraphWithLiteralAttribute", - pos: position{line: 1484, col: 1, offset: 56191}, + pos: position{line: 1485, col: 1, offset: 56209}, expr: &actionExpr{ - pos: position{line: 1485, col: 5, offset: 56229}, + pos: position{line: 1486, col: 5, offset: 56247}, run: (*parser).callonParagraphWithLiteralAttribute1, expr: &seqExpr{ - pos: position{line: 1485, col: 5, offset: 56229}, + pos: position{line: 1486, col: 5, offset: 56247}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1485, col: 5, offset: 56229}, + pos: position{line: 1486, col: 5, offset: 56247}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 1485, col: 16, offset: 56240}, + pos: position{line: 1486, col: 16, offset: 56258}, expr: &ruleRefExpr{ - pos: position{line: 1485, col: 17, offset: 56241}, + pos: position{line: 1486, col: 17, offset: 56259}, name: "ElementAttributes", }, }, }, &andCodeExpr{ - pos: position{line: 1486, col: 5, offset: 56265}, + pos: position{line: 1487, col: 5, offset: 56283}, run: (*parser).callonParagraphWithLiteralAttribute6, }, &labeledExpr{ - pos: position{line: 1493, col: 5, offset: 56479}, + pos: position{line: 1494, col: 5, offset: 56497}, label: "lines", expr: &ruleRefExpr{ - pos: position{line: 1493, col: 12, offset: 56486}, + pos: position{line: 1494, col: 12, offset: 56504}, name: "ParagraphWithLiteralAttributeLines", }, }, @@ -11668,12 +11672,12 @@ var g = &grammar{ }, { name: "LiteralKind", - pos: position{line: 1497, col: 1, offset: 56636}, + pos: position{line: 1498, col: 1, offset: 56654}, expr: &actionExpr{ - pos: position{line: 1497, col: 16, offset: 56651}, + pos: position{line: 1498, col: 16, offset: 56669}, run: (*parser).callonLiteralKind1, expr: &litMatcher{ - pos: position{line: 1497, col: 16, offset: 56651}, + pos: position{line: 1498, col: 16, offset: 56669}, val: "literal", ignoreCase: false, }, @@ -11681,17 +11685,17 @@ var g = &grammar{ }, { name: "ParagraphWithLiteralAttributeLines", - pos: position{line: 1502, col: 1, offset: 56734}, + pos: position{line: 1503, col: 1, offset: 56752}, expr: &actionExpr{ - pos: position{line: 1502, col: 39, offset: 56772}, + pos: position{line: 1503, col: 39, offset: 56790}, run: (*parser).callonParagraphWithLiteralAttributeLines1, expr: &labeledExpr{ - pos: position{line: 1502, col: 39, offset: 56772}, + pos: position{line: 1503, col: 39, offset: 56790}, label: "lines", expr: &oneOrMoreExpr{ - pos: position{line: 1502, col: 45, offset: 56778}, + pos: position{line: 1503, col: 45, offset: 56796}, expr: &ruleRefExpr{ - pos: position{line: 1502, col: 46, offset: 56779}, + pos: position{line: 1503, col: 46, offset: 56797}, name: "ParagraphWithLiteralAttributeLine", }, }, @@ -11700,54 +11704,54 @@ var g = &grammar{ }, { name: "ParagraphWithLiteralAttributeLine", - pos: position{line: 1506, col: 1, offset: 56859}, + pos: position{line: 1507, col: 1, offset: 56877}, expr: &actionExpr{ - pos: position{line: 1506, col: 38, offset: 56896}, + pos: position{line: 1507, col: 38, offset: 56914}, run: (*parser).callonParagraphWithLiteralAttributeLine1, expr: &seqExpr{ - pos: position{line: 1506, col: 38, offset: 56896}, + pos: position{line: 1507, col: 38, offset: 56914}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 1506, col: 38, offset: 56896}, + pos: position{line: 1507, col: 38, offset: 56914}, label: "line", expr: &actionExpr{ - pos: position{line: 1506, col: 44, offset: 56902}, + pos: position{line: 1507, col: 44, offset: 56920}, run: (*parser).callonParagraphWithLiteralAttributeLine4, expr: &seqExpr{ - pos: position{line: 1506, col: 44, offset: 56902}, + pos: position{line: 1507, col: 44, offset: 56920}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1506, col: 44, offset: 56902}, + pos: position{line: 1507, col: 44, offset: 56920}, expr: &ruleRefExpr{ - pos: position{line: 1506, col: 46, offset: 56904}, + pos: position{line: 1507, col: 46, offset: 56922}, name: "BlankLine", }, }, &oneOrMoreExpr{ - pos: position{line: 1506, col: 57, offset: 56915}, + pos: position{line: 1507, col: 57, offset: 56933}, expr: &choiceExpr{ - pos: position{line: 1506, col: 58, offset: 56916}, + pos: position{line: 1507, col: 58, offset: 56934}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1506, col: 58, offset: 56916}, + pos: position{line: 1507, col: 58, offset: 56934}, name: "Alphanums", }, &ruleRefExpr{ - pos: position{line: 1506, col: 70, offset: 56928}, + pos: position{line: 1507, col: 70, offset: 56946}, name: "Spaces", }, &seqExpr{ - pos: position{line: 1506, col: 80, offset: 56938}, + pos: position{line: 1507, col: 80, offset: 56956}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1506, col: 80, offset: 56938}, + pos: position{line: 1507, col: 80, offset: 56956}, expr: &ruleRefExpr{ - pos: position{line: 1506, col: 81, offset: 56939}, + pos: position{line: 1507, col: 81, offset: 56957}, name: "EOL", }, }, &anyMatcher{ - line: 1506, col: 86, offset: 56944, + line: 1507, col: 86, offset: 56962, }, }, }, @@ -11759,7 +11763,7 @@ var g = &grammar{ }, }, &ruleRefExpr{ - pos: position{line: 1508, col: 4, offset: 56985}, + pos: position{line: 1509, col: 4, offset: 57003}, name: "EOL", }, }, @@ -11768,22 +11772,22 @@ var g = &grammar{ }, { name: "BlankLine", - pos: position{line: 1515, col: 1, offset: 57157}, + pos: position{line: 1516, col: 1, offset: 57175}, expr: &actionExpr{ - pos: position{line: 1515, col: 14, offset: 57170}, + pos: position{line: 1516, col: 14, offset: 57188}, run: (*parser).callonBlankLine1, expr: &seqExpr{ - pos: position{line: 1515, col: 14, offset: 57170}, + pos: position{line: 1516, col: 14, offset: 57188}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1515, col: 14, offset: 57170}, + pos: position{line: 1516, col: 14, offset: 57188}, expr: &ruleRefExpr{ - pos: position{line: 1515, col: 15, offset: 57171}, + pos: position{line: 1516, col: 15, offset: 57189}, name: "EOF", }, }, &ruleRefExpr{ - pos: position{line: 1515, col: 19, offset: 57175}, + pos: position{line: 1516, col: 19, offset: 57193}, name: "EOLS", }, }, @@ -11792,9 +11796,9 @@ var g = &grammar{ }, { name: "Alphanum", - pos: position{line: 1522, col: 1, offset: 57323}, + pos: position{line: 1523, col: 1, offset: 57341}, expr: &charClassMatcher{ - pos: position{line: 1522, col: 13, offset: 57335}, + pos: position{line: 1523, col: 13, offset: 57353}, val: "[\\pL0-9]", ranges: []rune{'0', '9'}, classes: []*unicode.RangeTable{rangeTable("L")}, @@ -11804,37 +11808,37 @@ var g = &grammar{ }, { name: "Parenthesis", - pos: position{line: 1524, col: 1, offset: 57345}, + pos: position{line: 1525, col: 1, offset: 57363}, expr: &choiceExpr{ - pos: position{line: 1524, col: 16, offset: 57360}, + pos: position{line: 1525, col: 16, offset: 57378}, alternatives: []interface{}{ &litMatcher{ - pos: position{line: 1524, col: 16, offset: 57360}, + pos: position{line: 1525, col: 16, offset: 57378}, val: "(", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1524, col: 22, offset: 57366}, + pos: position{line: 1525, col: 22, offset: 57384}, val: ")", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1524, col: 28, offset: 57372}, + pos: position{line: 1525, col: 28, offset: 57390}, val: "[", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1524, col: 34, offset: 57378}, + pos: position{line: 1525, col: 34, offset: 57396}, val: "]", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1524, col: 40, offset: 57384}, + pos: position{line: 1525, col: 40, offset: 57402}, val: "{", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1524, col: 46, offset: 57390}, + pos: position{line: 1525, col: 46, offset: 57408}, val: "}", ignoreCase: false, }, @@ -11843,14 +11847,14 @@ var g = &grammar{ }, { name: "Alphanums", - pos: position{line: 1526, col: 1, offset: 57396}, + pos: position{line: 1527, col: 1, offset: 57414}, expr: &actionExpr{ - pos: position{line: 1526, col: 14, offset: 57409}, + pos: position{line: 1527, col: 14, offset: 57427}, run: (*parser).callonAlphanums1, expr: &oneOrMoreExpr{ - pos: position{line: 1526, col: 14, offset: 57409}, + pos: position{line: 1527, col: 14, offset: 57427}, expr: &charClassMatcher{ - pos: position{line: 1526, col: 14, offset: 57409}, + pos: position{line: 1527, col: 14, offset: 57427}, val: "[\\pL0-9]", ranges: []rune{'0', '9'}, classes: []*unicode.RangeTable{rangeTable("L")}, @@ -11862,37 +11866,37 @@ var g = &grammar{ }, { name: "Dot", - pos: position{line: 1530, col: 1, offset: 57455}, + pos: position{line: 1531, col: 1, offset: 57473}, expr: &litMatcher{ - pos: position{line: 1530, col: 8, offset: 57462}, + pos: position{line: 1531, col: 8, offset: 57480}, val: ".", ignoreCase: false, }, }, { name: "SimpleWord", - pos: position{line: 1532, col: 1, offset: 57467}, + pos: position{line: 1533, col: 1, offset: 57485}, expr: &actionExpr{ - pos: position{line: 1532, col: 15, offset: 57481}, + pos: position{line: 1533, col: 15, offset: 57499}, run: (*parser).callonSimpleWord1, expr: &seqExpr{ - pos: position{line: 1532, col: 15, offset: 57481}, + pos: position{line: 1533, col: 15, offset: 57499}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 1532, col: 15, offset: 57481}, + pos: position{line: 1533, col: 15, offset: 57499}, name: "Alphanums", }, &andExpr{ - pos: position{line: 1532, col: 25, offset: 57491}, + pos: position{line: 1533, col: 25, offset: 57509}, expr: &choiceExpr{ - pos: position{line: 1532, col: 27, offset: 57493}, + pos: position{line: 1533, col: 27, offset: 57511}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1532, col: 27, offset: 57493}, + pos: position{line: 1533, col: 27, offset: 57511}, name: "WS", }, &ruleRefExpr{ - pos: position{line: 1532, col: 32, offset: 57498}, + pos: position{line: 1533, col: 32, offset: 57516}, name: "EOL", }, }, @@ -11904,76 +11908,76 @@ var g = &grammar{ }, { name: "OtherWord", - pos: position{line: 1537, col: 1, offset: 57763}, + pos: position{line: 1538, col: 1, offset: 57781}, expr: &actionExpr{ - pos: position{line: 1537, col: 14, offset: 57776}, + pos: position{line: 1538, col: 14, offset: 57794}, run: (*parser).callonOtherWord1, expr: &choiceExpr{ - pos: position{line: 1537, col: 15, offset: 57777}, + pos: position{line: 1538, col: 15, offset: 57795}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1537, col: 15, offset: 57777}, + pos: position{line: 1538, col: 15, offset: 57795}, name: "Alphanums", }, &ruleRefExpr{ - pos: position{line: 1537, col: 27, offset: 57789}, + pos: position{line: 1538, col: 27, offset: 57807}, name: "QuotedTextPrefix", }, &oneOrMoreExpr{ - pos: position{line: 1537, col: 46, offset: 57808}, + pos: position{line: 1538, col: 46, offset: 57826}, expr: &actionExpr{ - pos: position{line: 1537, col: 47, offset: 57809}, + pos: position{line: 1538, col: 47, offset: 57827}, run: (*parser).callonOtherWord6, expr: &seqExpr{ - pos: position{line: 1537, col: 47, offset: 57809}, + pos: position{line: 1538, col: 47, offset: 57827}, exprs: []interface{}{ &seqExpr{ - pos: position{line: 1537, col: 48, offset: 57810}, + pos: position{line: 1538, col: 48, offset: 57828}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1537, col: 48, offset: 57810}, + pos: position{line: 1538, col: 48, offset: 57828}, expr: &ruleRefExpr{ - pos: position{line: 1537, col: 49, offset: 57811}, + pos: position{line: 1538, col: 49, offset: 57829}, name: "NEWLINE", }, }, ¬Expr{ - pos: position{line: 1537, col: 57, offset: 57819}, + pos: position{line: 1538, col: 57, offset: 57837}, expr: &ruleRefExpr{ - pos: position{line: 1537, col: 58, offset: 57820}, + pos: position{line: 1538, col: 58, offset: 57838}, name: "WS", }, }, ¬Expr{ - pos: position{line: 1537, col: 61, offset: 57823}, + pos: position{line: 1538, col: 61, offset: 57841}, expr: &ruleRefExpr{ - pos: position{line: 1537, col: 62, offset: 57824}, + pos: position{line: 1538, col: 62, offset: 57842}, name: "Dot", }, }, ¬Expr{ - pos: position{line: 1537, col: 66, offset: 57828}, + pos: position{line: 1538, col: 66, offset: 57846}, expr: &ruleRefExpr{ - pos: position{line: 1537, col: 67, offset: 57829}, + pos: position{line: 1538, col: 67, offset: 57847}, name: "QuotedTextPrefix", }, }, ¬Expr{ - pos: position{line: 1537, col: 84, offset: 57846}, + pos: position{line: 1538, col: 84, offset: 57864}, expr: &ruleRefExpr{ - pos: position{line: 1537, col: 85, offset: 57847}, + pos: position{line: 1538, col: 85, offset: 57865}, name: "Parenthesis", }, }, &anyMatcher{ - line: 1537, col: 97, offset: 57859, + line: 1538, col: 97, offset: 57877, }, }, }, &zeroOrOneExpr{ - pos: position{line: 1537, col: 100, offset: 57862}, + pos: position{line: 1538, col: 100, offset: 57880}, expr: &ruleRefExpr{ - pos: position{line: 1537, col: 100, offset: 57862}, + pos: position{line: 1538, col: 100, offset: 57880}, name: "Dot", }, }, @@ -11982,9 +11986,9 @@ var g = &grammar{ }, }, &oneOrMoreExpr{ - pos: position{line: 1539, col: 7, offset: 57971}, + pos: position{line: 1540, col: 7, offset: 57989}, expr: &litMatcher{ - pos: position{line: 1539, col: 7, offset: 57971}, + pos: position{line: 1540, col: 7, offset: 57989}, val: ".", ignoreCase: false, }, @@ -11995,35 +11999,35 @@ var g = &grammar{ }, { name: "Spaces", - pos: position{line: 1543, col: 1, offset: 58152}, + pos: position{line: 1544, col: 1, offset: 58170}, expr: &oneOrMoreExpr{ - pos: position{line: 1543, col: 11, offset: 58162}, + pos: position{line: 1544, col: 11, offset: 58180}, expr: &ruleRefExpr{ - pos: position{line: 1543, col: 11, offset: 58162}, + pos: position{line: 1544, col: 11, offset: 58180}, name: "WS", }, }, }, { name: "FileLocation", - pos: position{line: 1545, col: 1, offset: 58168}, + pos: position{line: 1546, col: 1, offset: 58186}, expr: &actionExpr{ - pos: position{line: 1545, col: 17, offset: 58184}, + pos: position{line: 1546, col: 17, offset: 58202}, run: (*parser).callonFileLocation1, expr: &labeledExpr{ - pos: position{line: 1545, col: 17, offset: 58184}, + pos: position{line: 1546, col: 17, offset: 58202}, label: "elements", expr: &oneOrMoreExpr{ - pos: position{line: 1545, col: 26, offset: 58193}, + pos: position{line: 1546, col: 26, offset: 58211}, expr: &choiceExpr{ - pos: position{line: 1545, col: 27, offset: 58194}, + pos: position{line: 1546, col: 27, offset: 58212}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1545, col: 27, offset: 58194}, + pos: position{line: 1546, col: 27, offset: 58212}, name: "FILENAME", }, &ruleRefExpr{ - pos: position{line: 1545, col: 38, offset: 58205}, + pos: position{line: 1546, col: 38, offset: 58223}, name: "DocumentAttributeSubstitution", }, }, @@ -12034,42 +12038,42 @@ var g = &grammar{ }, { name: "ResolvedFileLocation", - pos: position{line: 1549, col: 1, offset: 58297}, + pos: position{line: 1550, col: 1, offset: 58315}, expr: &actionExpr{ - pos: position{line: 1549, col: 25, offset: 58321}, + pos: position{line: 1550, col: 25, offset: 58339}, run: (*parser).callonResolvedFileLocation1, expr: &labeledExpr{ - pos: position{line: 1549, col: 25, offset: 58321}, + pos: position{line: 1550, col: 25, offset: 58339}, label: "elements", expr: &oneOrMoreExpr{ - pos: position{line: 1549, col: 34, offset: 58330}, + pos: position{line: 1550, col: 34, offset: 58348}, expr: &seqExpr{ - pos: position{line: 1549, col: 35, offset: 58331}, + pos: position{line: 1550, col: 35, offset: 58349}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1549, col: 35, offset: 58331}, + pos: position{line: 1550, col: 35, offset: 58349}, expr: &ruleRefExpr{ - pos: position{line: 1549, col: 36, offset: 58332}, + pos: position{line: 1550, col: 36, offset: 58350}, name: "EOL", }, }, ¬Expr{ - pos: position{line: 1549, col: 40, offset: 58336}, + pos: position{line: 1550, col: 40, offset: 58354}, expr: &ruleRefExpr{ - pos: position{line: 1549, col: 41, offset: 58337}, + pos: position{line: 1550, col: 41, offset: 58355}, name: "WS", }, }, ¬Expr{ - pos: position{line: 1549, col: 44, offset: 58340}, + pos: position{line: 1550, col: 44, offset: 58358}, expr: &litMatcher{ - pos: position{line: 1549, col: 45, offset: 58341}, + pos: position{line: 1550, col: 45, offset: 58359}, val: "[", ignoreCase: false, }, }, &anyMatcher{ - line: 1549, col: 49, offset: 58345, + line: 1550, col: 49, offset: 58363, }, }, }, @@ -12079,60 +12083,60 @@ var g = &grammar{ }, { name: "Location", - pos: position{line: 1553, col: 1, offset: 58409}, + pos: position{line: 1554, col: 1, offset: 58427}, expr: &actionExpr{ - pos: position{line: 1553, col: 13, offset: 58421}, + pos: position{line: 1554, col: 13, offset: 58439}, run: (*parser).callonLocation1, expr: &labeledExpr{ - pos: position{line: 1553, col: 13, offset: 58421}, + pos: position{line: 1554, col: 13, offset: 58439}, label: "elements", expr: &seqExpr{ - pos: position{line: 1553, col: 23, offset: 58431}, + pos: position{line: 1554, col: 23, offset: 58449}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 1553, col: 23, offset: 58431}, + pos: position{line: 1554, col: 23, offset: 58449}, name: "URL_SCHEME", }, &oneOrMoreExpr{ - pos: position{line: 1553, col: 34, offset: 58442}, + pos: position{line: 1554, col: 34, offset: 58460}, expr: &choiceExpr{ - pos: position{line: 1553, col: 35, offset: 58443}, + pos: position{line: 1554, col: 35, offset: 58461}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1553, col: 35, offset: 58443}, + pos: position{line: 1554, col: 35, offset: 58461}, name: "FILENAME", }, &ruleRefExpr{ - pos: position{line: 1553, col: 46, offset: 58454}, + pos: position{line: 1554, col: 46, offset: 58472}, name: "DocumentAttributeSubstitution", }, &seqExpr{ - pos: position{line: 1553, col: 78, offset: 58486}, + pos: position{line: 1554, col: 78, offset: 58504}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1553, col: 78, offset: 58486}, + pos: position{line: 1554, col: 78, offset: 58504}, expr: &ruleRefExpr{ - pos: position{line: 1553, col: 79, offset: 58487}, + pos: position{line: 1554, col: 79, offset: 58505}, name: "EOL", }, }, ¬Expr{ - pos: position{line: 1553, col: 83, offset: 58491}, + pos: position{line: 1554, col: 83, offset: 58509}, expr: &ruleRefExpr{ - pos: position{line: 1553, col: 84, offset: 58492}, + pos: position{line: 1554, col: 84, offset: 58510}, name: "WS", }, }, ¬Expr{ - pos: position{line: 1553, col: 87, offset: 58495}, + pos: position{line: 1554, col: 87, offset: 58513}, expr: &litMatcher{ - pos: position{line: 1553, col: 88, offset: 58496}, + pos: position{line: 1554, col: 88, offset: 58514}, val: "[", ignoreCase: false, }, }, &anyMatcher{ - line: 1553, col: 92, offset: 58500, + line: 1554, col: 92, offset: 58518, }, }, }, @@ -12146,26 +12150,26 @@ var g = &grammar{ }, { name: "FILENAME", - pos: position{line: 1557, col: 1, offset: 58565}, + pos: position{line: 1558, col: 1, offset: 58583}, expr: &oneOrMoreExpr{ - pos: position{line: 1557, col: 13, offset: 58577}, + pos: position{line: 1558, col: 13, offset: 58595}, expr: &choiceExpr{ - pos: position{line: 1557, col: 14, offset: 58578}, + pos: position{line: 1558, col: 14, offset: 58596}, alternatives: []interface{}{ &charClassMatcher{ - pos: position{line: 1557, col: 14, offset: 58578}, + pos: position{line: 1558, col: 14, offset: 58596}, val: "[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~:/?#@!$&;=()*+,_%]", chars: []rune{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '~', ':', '/', '?', '#', '@', '!', '$', '&', ';', '=', '(', ')', '*', '+', ',', '_', '%'}, ignoreCase: false, inverted: false, }, &litMatcher{ - pos: position{line: 1557, col: 99, offset: 58663}, + pos: position{line: 1558, col: 99, offset: 58681}, val: "-", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1557, col: 105, offset: 58669}, + pos: position{line: 1558, col: 105, offset: 58687}, val: ".", ignoreCase: false, }, @@ -12175,49 +12179,49 @@ var g = &grammar{ }, { name: "ResolvedLocation", - pos: position{line: 1559, col: 1, offset: 58790}, + pos: position{line: 1560, col: 1, offset: 58808}, expr: &actionExpr{ - pos: position{line: 1559, col: 21, offset: 58810}, + pos: position{line: 1560, col: 21, offset: 58828}, run: (*parser).callonResolvedLocation1, expr: &labeledExpr{ - pos: position{line: 1559, col: 21, offset: 58810}, + pos: position{line: 1560, col: 21, offset: 58828}, label: "elements", expr: &seqExpr{ - pos: position{line: 1559, col: 31, offset: 58820}, + pos: position{line: 1560, col: 31, offset: 58838}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 1559, col: 31, offset: 58820}, + pos: position{line: 1560, col: 31, offset: 58838}, name: "URL_SCHEME", }, &oneOrMoreExpr{ - pos: position{line: 1559, col: 42, offset: 58831}, + pos: position{line: 1560, col: 42, offset: 58849}, expr: &seqExpr{ - pos: position{line: 1559, col: 43, offset: 58832}, + pos: position{line: 1560, col: 43, offset: 58850}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1559, col: 43, offset: 58832}, + pos: position{line: 1560, col: 43, offset: 58850}, expr: &ruleRefExpr{ - pos: position{line: 1559, col: 44, offset: 58833}, + pos: position{line: 1560, col: 44, offset: 58851}, name: "EOL", }, }, ¬Expr{ - pos: position{line: 1559, col: 48, offset: 58837}, + pos: position{line: 1560, col: 48, offset: 58855}, expr: &ruleRefExpr{ - pos: position{line: 1559, col: 49, offset: 58838}, + pos: position{line: 1560, col: 49, offset: 58856}, name: "WS", }, }, ¬Expr{ - pos: position{line: 1559, col: 52, offset: 58841}, + pos: position{line: 1560, col: 52, offset: 58859}, expr: &litMatcher{ - pos: position{line: 1559, col: 53, offset: 58842}, + pos: position{line: 1560, col: 53, offset: 58860}, val: "[", ignoreCase: false, }, }, &anyMatcher{ - line: 1559, col: 57, offset: 58846, + line: 1560, col: 57, offset: 58864, }, }, }, @@ -12229,54 +12233,54 @@ var g = &grammar{ }, { name: "URL", - pos: position{line: 1564, col: 1, offset: 58912}, + pos: position{line: 1565, col: 1, offset: 58930}, expr: &actionExpr{ - pos: position{line: 1564, col: 8, offset: 58919}, + pos: position{line: 1565, col: 8, offset: 58937}, run: (*parser).callonURL1, expr: &oneOrMoreExpr{ - pos: position{line: 1564, col: 8, offset: 58919}, + pos: position{line: 1565, col: 8, offset: 58937}, expr: &choiceExpr{ - pos: position{line: 1564, col: 9, offset: 58920}, + pos: position{line: 1565, col: 9, offset: 58938}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1564, col: 9, offset: 58920}, + pos: position{line: 1565, col: 9, offset: 58938}, name: "Alphanums", }, &seqExpr{ - pos: position{line: 1564, col: 22, offset: 58933}, + pos: position{line: 1565, col: 22, offset: 58951}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1564, col: 22, offset: 58933}, + pos: position{line: 1565, col: 22, offset: 58951}, expr: &ruleRefExpr{ - pos: position{line: 1564, col: 23, offset: 58934}, + pos: position{line: 1565, col: 23, offset: 58952}, name: "NEWLINE", }, }, ¬Expr{ - pos: position{line: 1564, col: 31, offset: 58942}, + pos: position{line: 1565, col: 31, offset: 58960}, expr: &ruleRefExpr{ - pos: position{line: 1564, col: 32, offset: 58943}, + pos: position{line: 1565, col: 32, offset: 58961}, name: "WS", }, }, ¬Expr{ - pos: position{line: 1564, col: 35, offset: 58946}, + pos: position{line: 1565, col: 35, offset: 58964}, expr: &litMatcher{ - pos: position{line: 1564, col: 36, offset: 58947}, + pos: position{line: 1565, col: 36, offset: 58965}, val: "[", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 1564, col: 40, offset: 58951}, + pos: position{line: 1565, col: 40, offset: 58969}, expr: &litMatcher{ - pos: position{line: 1564, col: 41, offset: 58952}, + pos: position{line: 1565, col: 41, offset: 58970}, val: "]", ignoreCase: false, }, }, &anyMatcher{ - line: 1564, col: 46, offset: 58957, + line: 1565, col: 46, offset: 58975, }, }, }, @@ -12287,32 +12291,32 @@ var g = &grammar{ }, { name: "URL_SCHEME", - pos: position{line: 1568, col: 1, offset: 58998}, + pos: position{line: 1569, col: 1, offset: 59016}, expr: &choiceExpr{ - pos: position{line: 1568, col: 15, offset: 59012}, + pos: position{line: 1569, col: 15, offset: 59030}, alternatives: []interface{}{ &litMatcher{ - pos: position{line: 1568, col: 15, offset: 59012}, + pos: position{line: 1569, col: 15, offset: 59030}, val: "http://", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1568, col: 27, offset: 59024}, + pos: position{line: 1569, col: 27, offset: 59042}, val: "https://", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1568, col: 40, offset: 59037}, + pos: position{line: 1569, col: 40, offset: 59055}, val: "ftp://", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1568, col: 51, offset: 59048}, + pos: position{line: 1569, col: 51, offset: 59066}, val: "irc://", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1568, col: 62, offset: 59059}, + pos: position{line: 1569, col: 62, offset: 59077}, val: "mailto:", ignoreCase: false, }, @@ -12321,78 +12325,78 @@ var g = &grammar{ }, { name: "ID", - pos: position{line: 1570, col: 1, offset: 59070}, + pos: position{line: 1571, col: 1, offset: 59088}, expr: &actionExpr{ - pos: position{line: 1570, col: 7, offset: 59076}, + pos: position{line: 1571, col: 7, offset: 59094}, run: (*parser).callonID1, expr: &oneOrMoreExpr{ - pos: position{line: 1570, col: 7, offset: 59076}, + pos: position{line: 1571, col: 7, offset: 59094}, expr: &choiceExpr{ - pos: position{line: 1570, col: 8, offset: 59077}, + pos: position{line: 1571, col: 8, offset: 59095}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1570, col: 8, offset: 59077}, + pos: position{line: 1571, col: 8, offset: 59095}, name: "Alphanums", }, &seqExpr{ - pos: position{line: 1570, col: 21, offset: 59090}, + pos: position{line: 1571, col: 21, offset: 59108}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 1570, col: 21, offset: 59090}, + pos: position{line: 1571, col: 21, offset: 59108}, expr: &ruleRefExpr{ - pos: position{line: 1570, col: 22, offset: 59091}, + pos: position{line: 1571, col: 22, offset: 59109}, name: "NEWLINE", }, }, ¬Expr{ - pos: position{line: 1570, col: 30, offset: 59099}, + pos: position{line: 1571, col: 30, offset: 59117}, expr: &ruleRefExpr{ - pos: position{line: 1570, col: 31, offset: 59100}, + pos: position{line: 1571, col: 31, offset: 59118}, name: "WS", }, }, ¬Expr{ - pos: position{line: 1570, col: 34, offset: 59103}, + pos: position{line: 1571, col: 34, offset: 59121}, expr: &litMatcher{ - pos: position{line: 1570, col: 35, offset: 59104}, + pos: position{line: 1571, col: 35, offset: 59122}, val: "[", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 1570, col: 39, offset: 59108}, + pos: position{line: 1571, col: 39, offset: 59126}, expr: &litMatcher{ - pos: position{line: 1570, col: 40, offset: 59109}, + pos: position{line: 1571, col: 40, offset: 59127}, val: "]", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 1570, col: 44, offset: 59113}, + pos: position{line: 1571, col: 44, offset: 59131}, expr: &litMatcher{ - pos: position{line: 1570, col: 45, offset: 59114}, + pos: position{line: 1571, col: 45, offset: 59132}, val: "<<", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 1570, col: 50, offset: 59119}, + pos: position{line: 1571, col: 50, offset: 59137}, expr: &litMatcher{ - pos: position{line: 1570, col: 51, offset: 59120}, + pos: position{line: 1571, col: 51, offset: 59138}, val: ">>", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 1570, col: 56, offset: 59125}, + pos: position{line: 1571, col: 56, offset: 59143}, expr: &litMatcher{ - pos: position{line: 1570, col: 57, offset: 59126}, + pos: position{line: 1571, col: 57, offset: 59144}, val: ",", ignoreCase: false, }, }, &anyMatcher{ - line: 1570, col: 62, offset: 59131, + line: 1571, col: 62, offset: 59149, }, }, }, @@ -12403,12 +12407,12 @@ var g = &grammar{ }, { name: "DIGIT", - pos: position{line: 1574, col: 1, offset: 59172}, + pos: position{line: 1575, col: 1, offset: 59190}, expr: &actionExpr{ - pos: position{line: 1574, col: 10, offset: 59181}, + pos: position{line: 1575, col: 10, offset: 59199}, run: (*parser).callonDIGIT1, expr: &charClassMatcher{ - pos: position{line: 1574, col: 10, offset: 59181}, + pos: position{line: 1575, col: 10, offset: 59199}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -12418,25 +12422,25 @@ var g = &grammar{ }, { name: "NUMBER", - pos: position{line: 1578, col: 1, offset: 59223}, + pos: position{line: 1579, col: 1, offset: 59241}, expr: &actionExpr{ - pos: position{line: 1578, col: 11, offset: 59233}, + pos: position{line: 1579, col: 11, offset: 59251}, run: (*parser).callonNUMBER1, expr: &seqExpr{ - pos: position{line: 1578, col: 11, offset: 59233}, + pos: position{line: 1579, col: 11, offset: 59251}, exprs: []interface{}{ &zeroOrOneExpr{ - pos: position{line: 1578, col: 11, offset: 59233}, + pos: position{line: 1579, col: 11, offset: 59251}, expr: &litMatcher{ - pos: position{line: 1578, col: 11, offset: 59233}, + pos: position{line: 1579, col: 11, offset: 59251}, val: "-", ignoreCase: false, }, }, &oneOrMoreExpr{ - pos: position{line: 1578, col: 16, offset: 59238}, + pos: position{line: 1579, col: 16, offset: 59256}, expr: &ruleRefExpr{ - pos: position{line: 1578, col: 16, offset: 59238}, + pos: position{line: 1579, col: 16, offset: 59256}, name: "DIGIT", }, }, @@ -12446,20 +12450,20 @@ var g = &grammar{ }, { name: "WS", - pos: position{line: 1582, col: 1, offset: 59290}, + pos: position{line: 1583, col: 1, offset: 59308}, expr: &choiceExpr{ - pos: position{line: 1582, col: 7, offset: 59296}, + pos: position{line: 1583, col: 7, offset: 59314}, alternatives: []interface{}{ &litMatcher{ - pos: position{line: 1582, col: 7, offset: 59296}, + pos: position{line: 1583, col: 7, offset: 59314}, val: " ", ignoreCase: false, }, &actionExpr{ - pos: position{line: 1582, col: 13, offset: 59302}, + pos: position{line: 1583, col: 13, offset: 59320}, run: (*parser).callonWS3, expr: &litMatcher{ - pos: position{line: 1582, col: 13, offset: 59302}, + pos: position{line: 1583, col: 13, offset: 59320}, val: "\t", ignoreCase: false, }, @@ -12469,22 +12473,22 @@ var g = &grammar{ }, { name: "NEWLINE", - pos: position{line: 1586, col: 1, offset: 59343}, + pos: position{line: 1587, col: 1, offset: 59361}, expr: &choiceExpr{ - pos: position{line: 1586, col: 12, offset: 59354}, + pos: position{line: 1587, col: 12, offset: 59372}, alternatives: []interface{}{ &litMatcher{ - pos: position{line: 1586, col: 12, offset: 59354}, + pos: position{line: 1587, col: 12, offset: 59372}, val: "\r\n", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1586, col: 21, offset: 59363}, + pos: position{line: 1587, col: 21, offset: 59381}, val: "\r", ignoreCase: false, }, &litMatcher{ - pos: position{line: 1586, col: 28, offset: 59370}, + pos: position{line: 1587, col: 28, offset: 59388}, val: "\n", ignoreCase: false, }, @@ -12493,26 +12497,26 @@ var g = &grammar{ }, { name: "EOF", - pos: position{line: 1588, col: 1, offset: 59376}, + pos: position{line: 1589, col: 1, offset: 59394}, expr: ¬Expr{ - pos: position{line: 1588, col: 8, offset: 59383}, + pos: position{line: 1589, col: 8, offset: 59401}, expr: &anyMatcher{ - line: 1588, col: 9, offset: 59384, + line: 1589, col: 9, offset: 59402, }, }, }, { name: "EOL", - pos: position{line: 1590, col: 1, offset: 59387}, + pos: position{line: 1591, col: 1, offset: 59405}, expr: &choiceExpr{ - pos: position{line: 1590, col: 8, offset: 59394}, + pos: position{line: 1591, col: 8, offset: 59412}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 1590, col: 8, offset: 59394}, + pos: position{line: 1591, col: 8, offset: 59412}, name: "NEWLINE", }, &ruleRefExpr{ - pos: position{line: 1590, col: 18, offset: 59404}, + pos: position{line: 1591, col: 18, offset: 59422}, name: "EOF", }, }, @@ -12520,19 +12524,19 @@ var g = &grammar{ }, { name: "EOLS", - pos: position{line: 1592, col: 1, offset: 59409}, + pos: position{line: 1593, col: 1, offset: 59427}, expr: &seqExpr{ - pos: position{line: 1592, col: 9, offset: 59417}, + pos: position{line: 1593, col: 9, offset: 59435}, exprs: []interface{}{ &zeroOrMoreExpr{ - pos: position{line: 1592, col: 9, offset: 59417}, + pos: position{line: 1593, col: 9, offset: 59435}, expr: &ruleRefExpr{ - pos: position{line: 1592, col: 9, offset: 59417}, + pos: position{line: 1593, col: 9, offset: 59435}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 1592, col: 13, offset: 59421}, + pos: position{line: 1593, col: 13, offset: 59439}, name: "EOL", }, }, diff --git a/pkg/parser/parser.peg b/pkg/parser/parser.peg index c7736ab5..d1370b99 100644 --- a/pkg/parser/parser.peg +++ b/pkg/parser/parser.peg @@ -1145,7 +1145,8 @@ InlineLinks <- / Spaces / ResolvedLink / OtherWord - / Parenthesis)+ { + / Parenthesis + / NEWLINE)+ { return types.NewInlineElements(elements.([]interface{})) } diff --git a/pkg/parser/quoted_text_test.go b/pkg/parser/quoted_text_test.go index ad5b6696..78cfba90 100644 --- a/pkg/parser/quoted_text_test.go +++ b/pkg/parser/quoted_text_test.go @@ -8,195 +8,205 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("quoted texts - draft", func() { - - Context("quoted text with single punctuation", func() { - - It("bold text with 1 word", func() { - source := "*hello*" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "hello"}, +var _ = Describe("quoted texts", func() { + + Context("draft document", func() { + Context("quoted text with single punctuation", func() { + + It("bold text with 1 word", func() { + source := "*hello*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "hello"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("bold text with 2 words", func() { - source := "*bold content*" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "bold content"}, + It("bold text with 2 words", func() { + source := "*bold content*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("bold text with 3 words", func() { - source := "*some bold content*" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "some bold content"}, + It("bold text with 3 words", func() { + source := "*some bold content*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some bold content"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("italic text with 3 words in single quote", func() { - source := "_some italic content_" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "some italic content"}, + It("italic text with 3 words in single quote", func() { + source := "_some italic content_" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some italic content"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("monospace text with 3 words", func() { - source := "`some monospace content`" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "some monospace content"}, + It("monospace text with 3 words", func() { + source := "`some monospace content`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some monospace content"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("invalid subscript text with 3 words", func() { - source := "~some subscript content~" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "~some subscript content~"}, + It("invalid subscript text with 3 words", func() { + source := "~some subscript content~" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "~some subscript content~"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("invalid superscript text with 3 words", func() { - source := "^some superscript content^" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "^some superscript content^"}, + It("invalid superscript text with 3 words", func() { + source := "^some superscript content^" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "^some superscript content^"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("bold text within italic text", func() { - source := "_some *bold* content_" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "bold"}, + It("bold text within italic text", func() { + source := "_some *bold* content_" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold"}, + }, }, + types.StringElement{Content: " content"}, }, - types.StringElement{Content: " content"}, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("monospace text within bold text within italic quote", func() { - source := "*some _italic and `monospaced content`_*" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "italic and "}, - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "monospaced content"}, + It("monospace text within bold text within italic quote", func() { + source := "*some _italic and `monospaced content`_*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic and "}, + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "monospaced content"}, + }, }, }, }, @@ -206,202 +216,218 @@ var _ = Describe("quoted texts - draft", func() { }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("italic text within italic text", func() { - source := "_some _very italic_ content_" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "some _very italic"}, + It("italic text within italic text", func() { + source := "_some _very italic_ content_" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some _very italic"}, + }, + }, + types.StringElement{Content: " content_"}, + }, }, }, - types.StringElement{Content: " content_"}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("subscript text attached", func() { - source := "O~2~ is a molecule" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "O"}, - types.QuotedText{ - Kind: types.Subscript, - Elements: []interface{}{ - types.StringElement{Content: "2"}, + It("subscript text attached", func() { + source := "O~2~ is a molecule" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "O"}, + types.QuotedText{ + Kind: types.Subscript, + Elements: []interface{}{ + types.StringElement{Content: "2"}, + }, + }, + types.StringElement{Content: " is a molecule"}, + }, }, }, - types.StringElement{Content: " is a molecule"}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("superscript text attached", func() { - source := "M^me^ White" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "M"}, - types.QuotedText{ - Kind: types.Superscript, - Elements: []interface{}{ - types.StringElement{Content: "me"}, + It("superscript text attached", func() { + source := "M^me^ White" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "M"}, + types.QuotedText{ + Kind: types.Superscript, + Elements: []interface{}{ + types.StringElement{Content: "me"}, + }, + }, + types.StringElement{Content: " White"}, + }, }, }, - types.StringElement{Content: " White"}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("invalid subscript text with 3 words", func() { - source := "~some subscript content~" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "~some subscript content~"}, + It("invalid subscript text with 3 words", func() { + source := "~some subscript content~" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "~some subscript content~"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - Context("Quoted text with double punctuation", func() { + }) - It("bold text of 1 word in double quote", func() { - source := "**hello**" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "hello"}, + Context("Quoted text with double punctuation", func() { + + It("bold text of 1 word in double quote", func() { + source := "**hello**" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "hello"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("italic text with 3 words in double quote", func() { - source := "__some italic content__" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "some italic content"}, + It("italic text with 3 words in double quote", func() { + source := "__some italic content__" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some italic content"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("monospace text with 3 words in double quote", func() { - source := "``some monospace content``" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "some monospace content"}, + It("monospace text with 3 words in double quote", func() { + source := "``some monospace content``" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some monospace content"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("superscript text within italic text", func() { - source := "__some ^superscript^ content__" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Superscript, - Elements: []interface{}{ - types.StringElement{Content: "superscript"}, + It("superscript text within italic text", func() { + source := "__some ^superscript^ content__" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Superscript, + Elements: []interface{}{ + types.StringElement{Content: "superscript"}, + }, }, + types.StringElement{Content: " content"}, }, - types.StringElement{Content: " content"}, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("superscript text within italic text within bold quote", func() { - source := "**some _italic and ^superscriptcontent^_**" - expected := types.DraftDocument{ - Blocks: []interface{}{ - types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "italic and "}, - types.QuotedText{ - Kind: types.Superscript, - Elements: []interface{}{ - types.StringElement{Content: "superscriptcontent"}, + It("superscript text within italic text within bold quote", func() { + source := "**some _italic and ^superscriptcontent^_**" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic and "}, + types.QuotedText{ + Kind: types.Superscript, + Elements: []interface{}{ + types.StringElement{Content: "superscriptcontent"}, + }, }, }, }, @@ -411,771 +437,749 @@ var _ = Describe("quoted texts - draft", func() { }, }, }, - }, - } - Expect(source).To(BecomeDraftDocument(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) - }) - Context("Quoted text inline", func() { - - It("inline content with bold text", func() { - source := "a paragraph with *some bold content*" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a paragraph with "}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "some bold content"}, + Context("Quoted text inline", func() { + + It("inline content with bold text", func() { + source := "a paragraph with *some bold content*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some bold content"}, + }, + }, + }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("inline content with invalid bold text - use case 1", func() { - source := "a paragraph with *some bold content" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a paragraph with *some bold content"}, - }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("inline content with invalid bold text - use case 2", func() { - source := "a paragraph with *some bold content *" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a paragraph with *some bold content *"}, - }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("inline content with invalid bold text - use case 3", func() { - source := "a paragraph with * some bold content*" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a paragraph with * some bold content*"}, + It("inline content with invalid bold text - use case 1", func() { + source := "a paragraph with *some bold content" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with *some bold content"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("invalid italic text within bold text", func() { - source := "some *bold and _italic content _ together*." - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "bold and _italic content _ together"}, + It("inline content with invalid bold text - use case 2", func() { + source := "a paragraph with *some bold content *" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with *some bold content *"}, + }, }, }, - types.StringElement{Content: "."}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("italic text within invalid bold text", func() { - source := "some *bold and _italic content_ together *." - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "some *bold and "}, - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "italic content"}, + It("inline content with invalid bold text - use case 3", func() { + source := "a paragraph with * some bold content*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with * some bold content*"}, + }, }, }, - types.StringElement{Content: " together *."}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("inline content with invalid subscript text - use case 1", func() { - source := "a paragraph with ~some subscript content" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a paragraph with ~some subscript content"}, + It("invalid italic text within bold text", func() { + source := "some *bold and _italic content _ together*." + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold and _italic content _ together"}, + }, + }, + types.StringElement{Content: "."}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("inline content with invalid subscript text - use case 2", func() { - source := "a paragraph with ~some subscript content ~" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a paragraph with ~some subscript content ~"}, + It("italic text within invalid bold text", func() { + source := "some *bold and _italic content_ together *." + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "some *bold and "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic content"}, + }, + }, + types.StringElement{Content: " together *."}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("inline content with invalid subscript text - use case 3", func() { - source := "a paragraph with ~ some subscript content~" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a paragraph with ~ some subscript content~"}, + It("inline content with invalid subscript text - use case 1", func() { + source := "a paragraph with ~some subscript content" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with ~some subscript content"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("inline content with invalid superscript text - use case 1", func() { - source := "a paragraph with ^some superscript content" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - types.StringElement{Content: "a paragraph with ^some superscript content"}, + It("inline content with invalid subscript text - use case 2", func() { + source := "a paragraph with ~some subscript content ~" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with ~some subscript content ~"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("inline content with invalid superscript text - use case 2", func() { - source := "a paragraph with ^some superscript content ^" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - types.StringElement{Content: "a paragraph with ^some superscript content ^"}, + It("inline content with invalid subscript text - use case 3", func() { + source := "a paragraph with ~ some subscript content~" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with ~ some subscript content~"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("inline content with invalid superscript text - use case 3", func() { - source := "a paragraph with ^ some superscript content^" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - types.StringElement{Content: "a paragraph with ^ some superscript content^"}, - }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - }) + It("inline content with invalid superscript text - use case 1", func() { + source := "a paragraph with ^some superscript content" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { - Context("nested quoted text", func() { - - It("italic text within bold text", func() { - source := "some *bold and _italic content_ together*." - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "bold and "}, - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "italic content"}, - }, + types.StringElement{Content: "a paragraph with ^some superscript content"}, }, - types.StringElement{Content: " together"}, }, }, - types.StringElement{Content: "."}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("single-quote bold within single-quote bold text", func() { - // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "*some *nested bold* content*" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "some *nested bold"}, + It("inline content with invalid superscript text - use case 2", func() { + source := "a paragraph with ^some superscript content ^" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.StringElement{Content: "a paragraph with ^some superscript content ^"}, + }, }, }, - types.StringElement{Content: " content*"}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("double-quote bold within double-quote bold text", func() { - // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "**some **nested bold** content**" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - }, - }, - types.StringElement{Content: "nested bold"}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: " content"}, + It("inline content with invalid superscript text - use case 3", func() { + source := "a paragraph with ^ some superscript content^" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.StringElement{Content: "a paragraph with ^ some superscript content^"}, + }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) - It("single-quote bold within double-quote bold text", func() { - // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "**some *nested bold* content**" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "nested bold"}, + Context("nested quoted text", func() { + + It("italic text within bold text", func() { + source := "some *bold and _italic content_ together*." + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold and "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic content"}, + }, + }, + types.StringElement{Content: " together"}, + }, }, + types.StringElement{Content: "."}, }, - types.StringElement{Content: " content"}, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("double-quote bold within single-quote bold text", func() { - // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "*some **nested bold** content*" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "nested bold"}, + It("single-quote bold within single-quote bold text", func() { + // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "*some *nested bold* content*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some *nested bold"}, + }, }, + types.StringElement{Content: " content*"}, }, - types.StringElement{Content: " content"}, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("single-quote italic within single-quote italic text", func() { - // here we don't allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "_some _nested italic_ content_" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "some _nested italic"}, - }, - }, - types.StringElement{Content: " content_"}, - }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("double-quote italic within double-quote italic text", func() { - // here we don't allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "__some __nested italic__ content__" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - }, - }, - types.StringElement{Content: "nested italic"}, - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: " content"}, - }, - }, - }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("single-quote italic within double-quote italic text", func() { - // here we allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "_some __nested italic__ content_" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "nested italic"}, + It("double-quote bold within double-quote bold text", func() { + // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "**some **nested bold** content**" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + }, + }, + types.StringElement{Content: "nested bold"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: " content"}, + }, }, }, - types.StringElement{Content: " content"}, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("double-quote italic within single-quote italic text", func() { - // here we allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "_some __nested italic__ content_" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "nested italic"}, + It("single-quote bold within double-quote bold text", func() { + // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "**some *nested bold* content**" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "nested bold"}, + }, + }, + types.StringElement{Content: " content"}, + }, }, }, - types.StringElement{Content: " content"}, - }, - }, - }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("single-quote monospace within single-quote monospace text", func() { - // here we don't allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "`some `nested monospace` content`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "some `nested monospace"}, }, }, - types.StringElement{Content: " content`"}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("double-quote monospace within double-quote monospace text", func() { - // here we don't allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "``some ``nested monospace`` content``" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - }, - }, - types.StringElement{Content: "nested monospace"}, - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: " content"}, + It("double-quote bold within single-quote bold text", func() { + // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "*some **nested bold** content*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "nested bold"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("single-quote monospace within double-quote monospace text", func() { - // here we allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "`some ``nested monospace`` content`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "nested monospace"}, + It("single-quote italic within single-quote italic text", func() { + // here we don't allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "_some _nested italic_ content_" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some _nested italic"}, + }, }, + types.StringElement{Content: " content_"}, }, - types.StringElement{Content: " content"}, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("double-quote monospace within single-quote monospace text", func() { - // here we allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) - source := "`some ``nested monospace`` content`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "some "}, - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "nested monospace"}, + It("double-quote italic within double-quote italic text", func() { + // here we don't allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "__some __nested italic__ content__" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + }, + }, + types.StringElement{Content: "nested italic"}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: " content"}, + }, }, }, - types.StringElement{Content: " content"}, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("unbalanced bold in monospace - case 1", func() { - source := "`*a`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "*a"}, + It("single-quote italic within double-quote italic text", func() { + // here we allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "_some __nested italic__ content_" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "nested italic"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("unbalanced bold in monospace - case 2", func() { - source := "`a*b`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a*b"}, + It("double-quote italic within single-quote italic text", func() { + // here we allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "_some __nested italic__ content_" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "nested italic"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("italic in monospace", func() { - source := "`_a_`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "a"}, + It("single-quote monospace within single-quote monospace text", func() { + // here we don't allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "`some `nested monospace` content`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some `nested monospace"}, + }, }, + types.StringElement{Content: " content`"}, }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("unbalanced italic in monospace", func() { - source := "`a_b`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a_b"}, + It("double-quote monospace within double-quote monospace text", func() { + // here we don't allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "``some ``nested monospace`` content``" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + }, + }, + types.StringElement{Content: "nested monospace"}, + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: " content"}, + }, + }, + }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("unparsed bold in monospace", func() { - source := "`a*b*`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a*b*"}, + It("single-quote monospace within double-quote monospace text", func() { + // here we allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "`some ``nested monospace`` content`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "nested monospace"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("parsed subscript in monospace", func() { - source := "`a~b~`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a"}, - types.QuotedText{ - Kind: types.Subscript, - Elements: []interface{}{ - types.StringElement{Content: "b"}, + It("double-quote monospace within single-quote monospace text", func() { + // here we allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "`some ``nested monospace`` content`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "nested monospace"}, + }, + }, + types.StringElement{Content: " content"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("multiline in single quoted monospace - case 1", func() { - source := "`a\nb`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a\nb"}, + It("unbalanced bold in monospace - case 1", func() { + source := "`*a`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "*a"}, + }, + }, + }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("multiline in double quoted monospace - case 1", func() { - source := "`a\nb`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a\nb"}, + It("unbalanced bold in monospace - case 2", func() { + source := "`a*b`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a*b"}, + }, + }, + }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("multiline in single quoted monospace - case 2", func() { - source := "`a\n*b*`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a\n"}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "b"}, + It("italic in monospace", func() { + source := "`_a_`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "a"}, + }, + }, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("multiline in double quoted monospace - case 2", func() { - source := "`a\n*b*`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a\n"}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "b"}, + It("unbalanced italic in monospace", func() { + source := "`a_b`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a_b"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("link in bold", func() { - source := "*a link:/[b]*" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.InlineLink{ - Attributes: types.ElementAttributes{ - types.AttrInlineLinkText: []interface{}{ - types.StringElement{ - Content: "b", - }, - }, - }, - Location: types.Location{ + It("unparsed bold in monospace", func() { + source := "`a*b*`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, Elements: []interface{}{ - types.StringElement{ - Content: "/", - }, + types.StringElement{Content: "a*b*"}, }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("image in bold", func() { - source := "*a image:foo.png[]*" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.InlineImage{ - Attributes: types.ElementAttributes{}, - Location: types.Location{ + It("parsed subscript in monospace", func() { + source := "`a~b~`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, Elements: []interface{}{ - types.StringElement{ - Content: "foo.png", + types.StringElement{Content: "a"}, + types.QuotedText{ + Kind: types.Subscript, + Elements: []interface{}{ + types.StringElement{Content: "b"}, + }, }, }, }, @@ -1183,81 +1187,71 @@ var _ = Describe("quoted texts - draft", func() { }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("singleplus passthrough in bold", func() { - source := "*a +image:foo.png[]+*" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.Passthrough{ - Kind: types.SinglePlusPassthrough, - Elements: []interface{}{ - types.StringElement{Content: "image:foo.png[]"}, + It("multiline in single quoted monospace - case 1", func() { + source := "`a\nb`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a\nb"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("tripleplus passthrough in bold", func() { - source := "*a +++image:foo.png[]+++*" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.Passthrough{ - Kind: types.TriplePlusPassthrough, - Elements: []interface{}{ - types.StringElement{Content: "image:foo.png[]"}, + It("multiline in double quoted monospace - case 1", func() { + source := "`a\nb`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a\nb"}, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("link in italic", func() { - source := "_a link:/[b]_" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.InlineLink{ - Attributes: types.ElementAttributes{ - types.AttrInlineLinkText: []interface{}{ - types.StringElement{ - Content: "b", - }, - }, - }, - Location: types.Location{ + It("multiline in single quoted monospace - case 2", func() { + source := "`a\n*b*`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, Elements: []interface{}{ - types.StringElement{ - Content: "/", + types.StringElement{Content: "a\n"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "b"}, + }, }, }, }, @@ -1265,27 +1259,27 @@ var _ = Describe("quoted texts - draft", func() { }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("image in italic", func() { - source := "_a image:foo.png[]_" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.InlineImage{ - Attributes: types.ElementAttributes{}, - Location: types.Location{ + It("multiline in double quoted monospace - case 2", func() { + source := "`a\n*b*`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, Elements: []interface{}{ - types.StringElement{ - Content: "foo.png", + types.StringElement{Content: "a\n"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "b"}, + }, }, }, }, @@ -1293,81 +1287,97 @@ var _ = Describe("quoted texts - draft", func() { }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("singleplus passthrough in italic", func() { - source := "_a +image:foo.png[]+_" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.Passthrough{ - Kind: types.SinglePlusPassthrough, - Elements: []interface{}{ - types.StringElement{Content: "image:foo.png[]"}, + It("link in bold", func() { + source := "*a link:/[b]*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineLink{ + Attributes: types.ElementAttributes{ + types.AttrInlineLinkText: []interface{}{ + types.StringElement{ + Content: "b", + }, + }, + }, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "/", + }, + }, + }, + }, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("tripleplus passthrough in italic", func() { - source := "_a +++image:foo.png[]+++_" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.Passthrough{ - Kind: types.TriplePlusPassthrough, - Elements: []interface{}{ - types.StringElement{Content: "image:foo.png[]"}, + It("image in bold", func() { + source := "*a image:foo.png[]*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineImage{ + Attributes: types.ElementAttributes{}, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "foo.png", + }, + }, + }, + }, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("link in monospace", func() { - source := "`a link:/[b]`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.InlineLink{ - Attributes: types.ElementAttributes{ - types.AttrInlineLinkText: []interface{}{ - types.StringElement{ - Content: "b", - }, - }, - }, - Location: types.Location{ + It("singleplus passthrough in bold", func() { + source := "*a +image:foo.png[]+*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, Elements: []interface{}{ - types.StringElement{ - Content: "/", + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.SinglePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, }, }, }, @@ -1375,27 +1385,27 @@ var _ = Describe("quoted texts - draft", func() { }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - It("image in monospace", func() { - source := "`a image:foo.png[]`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.InlineImage{ - Attributes: types.ElementAttributes{}, - Location: types.Location{ + It("tripleplus passthrough in bold", func() { + source := "*a +++image:foo.png[]+++*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, Elements: []interface{}{ - types.StringElement{ - Content: "foo.png", + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.TriplePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, }, }, }, @@ -1403,816 +1413,4222 @@ var _ = Describe("quoted texts - draft", func() { }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("singleplus passthrough in monospace", func() { - source := "`a +image:foo.png[]+`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.Passthrough{ - Kind: types.SinglePlusPassthrough, - Elements: []interface{}{ - types.StringElement{Content: "image:foo.png[]"}, + It("link in italic", func() { + source := "_a link:/[b]_" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineLink{ + Attributes: types.ElementAttributes{ + types.AttrInlineLinkText: []interface{}{ + types.StringElement{ + Content: "b", + }, + }, + }, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "/", + }, + }, + }, + }, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("tripleplus passthrough in monospace", func() { - source := "`a +++image:foo.png[]+++`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "a "}, - types.Passthrough{ - Kind: types.TriplePlusPassthrough, - Elements: []interface{}{ - types.StringElement{Content: "image:foo.png[]"}, + It("image in italic", func() { + source := "_a image:foo.png[]_" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineImage{ + Attributes: types.ElementAttributes{}, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "foo.png", + }, + }, + }, + }, + }, }, }, }, }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - }) - - Context("unbalanced quoted text", func() { - - Context("unbalanced bold text", func() { - - It("unbalanced bold text - extra on left", func() { - source := "**some bold content*" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { + } + Expect(source).To(BecomeDraftDocument(expected)) + }) - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "*some bold content"}, + It("singleplus passthrough in italic", func() { + source := "_a +image:foo.png[]+_" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.SinglePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, + }, + }, + }, }, }, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) - It("unbalanced bold text - extra on right", func() { - source := "*some bold content**" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "some bold content"}, + It("tripleplus passthrough in italic", func() { + source := "_a +++image:foo.png[]+++_" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.TriplePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, + }, + }, + }, }, }, - types.StringElement{Content: "*"}, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) - }) - - Context("unbalanced italic text", func() { - - It("unbalanced italic text - extra on left", func() { - source := "__some italic content_" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "_some italic content"}, + It("link in monospace", func() { + source := "`a link:/[b]`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineLink{ + Attributes: types.ElementAttributes{ + types.AttrInlineLinkText: []interface{}{ + types.StringElement{ + Content: "b", + }, + }, + }, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "/", + }, + }, + }, + }, + }, + }, }, }, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) - It("unbalanced italic text - extra on right", func() { - source := "_some italic content__" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "some italic content"}, + It("image in monospace", func() { + source := "`a image:foo.png[]`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineImage{ + Attributes: types.ElementAttributes{}, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "foo.png", + }, + }, + }, + }, + }, + }, }, }, - types.StringElement{Content: "_"}, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) - }) - Context("unbalanced monospace text", func() { - - It("unbalanced monospace text - extra on left", func() { - source := "``some monospace content`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "`some monospace content"}, + It("singleplus passthrough in monospace", func() { + source := "`a +image:foo.png[]+`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.SinglePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, + }, + }, + }, }, }, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) - It("unbalanced monospace text - extra on right", func() { - source := "`some monospace content``" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "some monospace content"}, + It("tripleplus passthrough in monospace", func() { + source := "`a +++image:foo.png[]+++`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.TriplePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, + }, + }, + }, }, }, - types.StringElement{Content: "`"}, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) - }) - It("inline content with unbalanced bold text", func() { - source := "a paragraph with *some bold content" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "a paragraph with *some bold content"}, - }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) }) - }) - - Context("prevented substitution", func() { - - Context("prevented bold text substitution", func() { + Context("unbalanced quoted text", func() { - Context("without nested quoted text", func() { + Context("unbalanced bold text", func() { - It("escaped bold text with single backslash", func() { - source := `\*bold content*` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "*bold content*"}, + It("unbalanced bold text - extra on left", func() { + source := "**some bold content*" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "*some bold content"}, + }, + }, + }, + }, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) - It("escaped bold text with multiple backslashes", func() { - source := `\\*bold content*` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\*bold content*`}, - }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + It("unbalanced bold text - extra on right", func() { + source := "*some bold content**" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { - It("escaped bold text with double quote", func() { - source := `\\**bold content**` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `**bold content**`}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some bold content"}, + }, + }, + types.StringElement{Content: "*"}, + }, + }, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) + }) - It("escaped bold text with double quote and more backslashes", func() { - source := `\\\**bold content**` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\**bold content**`}, - }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + Context("unbalanced italic text", func() { + + It("unbalanced italic text - extra on left", func() { + source := "__some italic content_" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { - It("escaped bold text with unbalanced double quote", func() { - source := `\**bold content*` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `**bold content*`}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "_some italic content"}, + }, + }, + }, + }, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) - It("escaped bold text with unbalanced double quote and more backslashes", func() { - source := `\\\**bold content*` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\\**bold content*`}, + It("unbalanced italic text - extra on right", func() { + source := "_some italic content__" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some italic content"}, + }, + }, + types.StringElement{Content: "_"}, + }, + }, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) }) - Context("with nested quoted text", func() { + Context("unbalanced monospace text", func() { - It("escaped bold text with nested italic text", func() { - source := `\*_italic content_*` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "*"}, - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "italic content"}, + It("unbalanced monospace text - extra on left", func() { + source := "``some monospace content`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "`some monospace content"}, + }, + }, }, }, - types.StringElement{Content: "*"}, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) - It("escaped bold text with unbalanced double quote and nested italic test", func() { - source := `\**_italic content_*` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "**"}, - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "italic content"}, + It("unbalanced monospace text - extra on right", func() { + source := "`some monospace content``" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some monospace content"}, + }, + }, + types.StringElement{Content: "`"}, }, }, - types.StringElement{Content: "*"}, }, }, } - Expect(source).To(BecomeDocumentBlock(expected)) + Expect(source).To(BecomeDraftDocument(expected)) }) + }) - It("escaped bold text with nested italic", func() { - source := `\*bold _and italic_ content*` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "*bold "}, - types.QuotedText{ - Kind: types.Italic, - Elements: []interface{}{ - types.StringElement{Content: "and italic"}, - }, + It("inline content with unbalanced bold text", func() { + source := "a paragraph with *some bold content" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with *some bold content"}, }, - types.StringElement{Content: " content*"}, }, }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + }, + } + Expect(source).To(BecomeDraftDocument(expected)) }) }) - Context("prevented italic text substitution", func() { + Context("prevented substitution", func() { - Context("without nested quoted text", func() { + Context("prevented bold text substitution", func() { - It("escaped italic text with single quote", func() { - source := `\_italic content_` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "_italic content_"}, - }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + Context("without nested quoted text", func() { - It("escaped italic text with single quote and more backslashes", func() { - source := `\\_italic content_` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\_italic content_`}, + It("escaped bold text with single backslash", func() { + source := `\*bold content*` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "*bold content*"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("escaped italic text with double quote with 2 backslashes", func() { - source := `\\__italic content__` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `__italic content__`}, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped bold text with multiple backslashes", func() { + source := `\\*bold content*` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\*bold content*`}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("escaped italic text with double quote with 3 backslashes", func() { - source := `\\\__italic content__` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\__italic content__`}, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped bold text with double quote", func() { + source := `\\**bold content**` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `**bold content**`}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("escaped italic text with unbalanced double quote", func() { - source := `\__italic content_` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `__italic content_`}, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped bold text with double quote and more backslashes", func() { + source := `\\\**bold content**` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\**bold content**`}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("escaped italic text with unbalanced double quote and more backslashes", func() { - source := `\\\__italic content_` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\\__italic content_`}, // only 1 backslash remove + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped bold text with unbalanced double quote", func() { + source := `\**bold content*` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `**bold content*`}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped bold text with unbalanced double quote and more backslashes", func() { + source := `\\\**bold content*` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\\**bold content*`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) - }) - Context("with nested quoted text", func() { + Context("with nested quoted text", func() { - It("escaped italic text with nested monospace text", func() { - source := `\` + "_`monospace content`_" // gives: \_`monospace content`_ - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "_"}, - types.QuotedText{ - Kind: types.Monospace, - Elements: []interface{}{ - types.StringElement{Content: "monospace content"}, + It("escaped bold text with nested italic text", func() { + source := `\*_italic content_*` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "*"}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic content"}, + }, + }, + types.StringElement{Content: "*"}, + }, }, }, - types.StringElement{Content: "_"}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("escaped italic text with unbalanced double quote and nested bold test", func() { - source := `\__*bold content*_` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "__"}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "bold content"}, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped bold text with unbalanced double quote and nested italic test", func() { + source := `\**_italic content_*` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "**"}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic content"}, + }, + }, + types.StringElement{Content: "*"}, + }, }, }, - types.StringElement{Content: "_"}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("escaped italic text with nested bold text", func() { - source := `\_italic *and bold* content_` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "_italic "}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "and bold"}, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped bold text with nested italic", func() { + source := `\*bold _and italic_ content*` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "*bold "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "and italic"}, + }, + }, + types.StringElement{Content: " content*"}, + }, }, }, - types.StringElement{Content: " content_"}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) + }) - }) - Context("prevented monospace text substitution", func() { + Context("prevented italic text substitution", func() { - Context("without nested quoted text", func() { + Context("without nested quoted text", func() { - It("escaped monospace text with single quote", func() { - source := `\` + "`monospace content`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "`monospace content`"}, // backslash removed + It("escaped italic text with single quote", func() { + source := `\_italic content_` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "_italic content_"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("escaped monospace text with single quote and more backslashes", func() { - source := `\\` + "`monospace content`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\` + "`monospace content`"}, // only 1 backslash removed + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped italic text with single quote and more backslashes", func() { + source := `\\_italic content_` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\_italic content_`}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("escaped monospace text with double quote", func() { - source := `\\` + "`monospace content``" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\` + "`monospace content``"}, // 2 back slashes "consumed" + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped italic text with double quote with 2 backslashes", func() { + source := `\\__italic content__` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `__italic content__`}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped italic text with double quote with 3 backslashes", func() { + source := `\\\__italic content__` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\__italic content__`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped italic text with unbalanced double quote", func() { + source := `\__italic content_` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `__italic content_`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped italic text with unbalanced double quote and more backslashes", func() { + source := `\\\__italic content_` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\\__italic content_`}, // only 1 backslash remove + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) - It("escaped monospace text with double quote and more backslashes", func() { - source := `\\\` + "``monospace content``" // 3 backslashes - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\` + "``monospace content``"}, // 2 back slashes "consumed" + Context("with nested quoted text", func() { + + It("escaped italic text with nested monospace text", func() { + source := `\` + "_`monospace content`_" // gives: \_`monospace content`_ + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "_"}, + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "monospace content"}, + }, + }, + types.StringElement{Content: "_"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped italic text with unbalanced double quote and nested bold test", func() { + source := `\__*bold content*_` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "__"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, + }, + types.StringElement{Content: "_"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped italic text with nested bold text", func() { + source := `\_italic *and bold* content_` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "_italic "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "and bold"}, + }, + }, + types.StringElement{Content: " content_"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) + }) - It("escaped monospace text with unbalanced double quote", func() { - source := `\` + "``monospace content`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "``monospace content`"}, + Context("prevented monospace text substitution", func() { + + Context("without nested quoted text", func() { + + It("escaped monospace text with single quote", func() { + source := `\` + "`monospace content`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "`monospace content`"}, // backslash removed + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped monospace text with single quote and more backslashes", func() { + source := `\\` + "`monospace content`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\` + "`monospace content`"}, // only 1 backslash removed + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped monospace text with double quote", func() { + source := `\\` + "`monospace content``" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\` + "`monospace content``"}, // 2 back slashes "consumed" + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped monospace text with double quote and more backslashes", func() { + source := `\\\` + "``monospace content``" // 3 backslashes + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\` + "``monospace content``"}, // 2 back slashes "consumed" + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped monospace text with unbalanced double quote", func() { + source := `\` + "``monospace content`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "``monospace content`"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped monospace text with unbalanced double quote and more backslashes", func() { + source := `\\\` + "``monospace content`" // 3 backslashes + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\\` + "``monospace content`"}, // 2 backslashes removed + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) - It("escaped monospace text with unbalanced double quote and more backslashes", func() { - source := `\\\` + "``monospace content`" // 3 backslashes - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\\` + "``monospace content`"}, // 2 backslashes removed + Context("with nested quoted text", func() { + + It("escaped monospace text with nested bold text", func() { + source := `\` + "`*bold content*`" // gives: \`*bold content*` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "`"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, + }, + types.StringElement{Content: "`"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped monospace text with unbalanced double backquote and nested bold test", func() { + source := `\` + "``*bold content*`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "``"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, + }, + types.StringElement{Content: "`"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped monospace text with nested bold text", func() { + source := `\` + "`monospace *and bold* content`" + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "`monospace "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "and bold"}, + }, + }, + types.StringElement{Content: " content`"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) }) - Context("with nested quoted text", func() { + Context("prevented subscript text substitution", func() { - It("escaped monospace text with nested bold text", func() { - source := `\` + "`*bold content*`" // gives: \`*bold content*` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "`"}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "bold content"}, + Context("without nested quoted text", func() { + + It("escaped subscript text with single quote", func() { + source := `\~subscriptcontent~` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "~subscriptcontent~"}, + }, }, }, - types.StringElement{Content: "`"}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) - - It("escaped monospace text with unbalanced double backquote and nested bold test", func() { - source := `\` + "``*bold content*`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "``"}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "bold content"}, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped subscript text with single quote and more backslashes", func() { + source := `\\~subscriptcontent~` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\~subscriptcontent~`}, // only 1 backslash removed + }, }, }, - types.StringElement{Content: "`"}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + }) - It("escaped monospace text with nested bold text", func() { - source := `\` + "`monospace *and bold* content`" - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "`monospace "}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "and bold"}, + Context("with nested quoted text", func() { + + It("escaped subscript text with nested bold text", func() { + source := `\~*boldcontent*~` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "~"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "boldcontent"}, + }, + }, + types.StringElement{Content: "~"}, + }, }, }, - types.StringElement{Content: " content`"}, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped subscript text with nested bold text", func() { + source := `\~subscript *and bold* content~` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\~subscript `}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "and bold"}, + }, + }, + types.StringElement{Content: " content~"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) }) - }) - Context("prevented subscript text substitution", func() { + Context("prevented superscript text substitution", func() { - Context("without nested quoted text", func() { + Context("without nested quoted text", func() { - It("escaped subscript text with single quote", func() { - source := `\~subscriptcontent~` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "~subscriptcontent~"}, + It("escaped superscript text with single quote", func() { + source := `\^superscriptcontent^` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "^superscriptcontent^"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped superscript text with single quote and more backslashes", func() { + source := `\\^superscriptcontent^` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\^superscriptcontent^`}, // only 1 backslash removed + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + }) - It("escaped subscript text with single quote and more backslashes", func() { - source := `\\~subscriptcontent~` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\~subscriptcontent~`}, // only 1 backslash removed + Context("with nested quoted text", func() { + + It("escaped superscript text with nested bold text - case 1", func() { + source := `\^*bold content*^` // valid escaped superscript since it has no space within + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `^`}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, + }, + types.StringElement{Content: "^"}, + }, + }, + }, }, - }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped superscript text with unbalanced double backquote and nested bold test", func() { + source := `\^*bold content*^` + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "^"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, + }, + types.StringElement{Content: "^"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) + + It("escaped superscript text with nested bold text - case 2", func() { + source := `\^superscript *and bold* content^` // invalid superscript text since it has spaces within + expected := types.DraftDocument{ + Blocks: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\^superscript `}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "and bold"}, + }, + }, + types.StringElement{Content: " content^"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDraftDocument(expected)) + }) }) - }) + }) + }) - Context("with nested quoted text", func() { - - It("escaped subscript text with nested bold text", func() { - source := `\~*boldcontent*~` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "~"}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "boldcontent"}, + Context("final document", func() { + Context("quoted text with single punctuation", func() { + + It("bold text with 1 word", func() { + source := "*hello*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "hello"}, + }, }, }, - types.StringElement{Content: "~"}, }, }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + }, + } + Expect(source).To(BecomeDocument(expected)) + }) - It("escaped subscript text with nested bold text", func() { - source := `\~subscript *and bold* content~` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\~subscript `}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "and bold"}, + It("bold text with 2 words", func() { + source := "*bold content*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, }, }, - types.StringElement{Content: " content~"}, }, }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + }, + } + Expect(source).To(BecomeDocument(expected)) }) - }) - Context("prevented superscript text substitution", func() { + It("bold text with 3 words", func() { + source := "*some bold content*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some bold content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) - Context("without nested quoted text", func() { + It("italic text with 3 words in single quote", func() { + source := "_some italic content_" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some italic content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) - It("escaped superscript text with single quote", func() { - source := `\^superscriptcontent^` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "^superscriptcontent^"}, + It("monospace text with 3 words", func() { + source := "`some monospace content`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some monospace content"}, + }, + }, + }, }, }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + }, + } + Expect(source).To(BecomeDocument(expected)) + }) - It("escaped superscript text with single quote and more backslashes", func() { - source := `\\^superscriptcontent^` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\^superscriptcontent^`}, // only 1 backslash removed + It("invalid subscript text with 3 words", func() { + source := "~some subscript content~" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "~some subscript content~"}, + }, }, }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + It("invalid superscript text with 3 words", func() { + source := "^some superscript content^" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "^some superscript content^"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) }) - Context("with nested quoted text", func() { + It("bold text within italic text", func() { + source := "_some *bold* content_" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) - It("escaped superscript text with nested bold text - case 1", func() { - source := `\^*bold content*^` // valid escaped superscript since it has no space within - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `^`}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "bold content"}, + It("monospace text within bold text within italic quote", func() { + source := "*some _italic and `monospaced content`_*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic and "}, + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "monospaced content"}, + }, + }, + }, + }, + }, }, }, - types.StringElement{Content: "^"}, }, }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + }, + } + Expect(source).To(BecomeDocument(expected)) + }) - It("escaped superscript text with unbalanced double backquote and nested bold test", func() { - source := `\^*bold content*^` - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: "^"}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "bold content"}, + It("italic text within italic text", func() { + source := "_some _very italic_ content_" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some _very italic"}, + }, }, + types.StringElement{Content: " content_"}, }, - types.StringElement{Content: "^"}, }, }, - } - Expect(source).To(BecomeDocumentBlock(expected)) - }) + }, + } + Expect(source).To(BecomeDocument(expected)) + }) - It("escaped superscript text with nested bold text - case 2", func() { - source := `\^superscript *and bold* content^` // invalid superscript text since it has spaces within - expected := types.Paragraph{ - Attributes: types.ElementAttributes{}, - Lines: [][]interface{}{ - { - types.StringElement{Content: `\^superscript `}, - types.QuotedText{ - Kind: types.Bold, - Elements: []interface{}{ - types.StringElement{Content: "and bold"}, + It("subscript text attached", func() { + source := "O~2~ is a molecule" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "O"}, + types.QuotedText{ + Kind: types.Subscript, + Elements: []interface{}{ + types.StringElement{Content: "2"}, + }, }, + types.StringElement{Content: " is a molecule"}, }, - types.StringElement{Content: " content^"}, }, }, - } - Expect(source).To(BecomeDocumentBlock(expected)) + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("superscript text attached", func() { + source := "M^me^ White" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "M"}, + types.QuotedText{ + Kind: types.Superscript, + Elements: []interface{}{ + types.StringElement{Content: "me"}, + }, + }, + types.StringElement{Content: " White"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("invalid subscript text with 3 words", func() { + source := "~some subscript content~" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "~some subscript content~"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + }) + + Context("Quoted text with double punctuation", func() { + + It("bold text of 1 word in double quote", func() { + source := "**hello**" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "hello"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("italic text with 3 words in double quote", func() { + source := "__some italic content__" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some italic content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("monospace text with 3 words in double quote", func() { + source := "``some monospace content``" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some monospace content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("superscript text within italic text", func() { + source := "__some ^superscript^ content__" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Superscript, + Elements: []interface{}{ + types.StringElement{Content: "superscript"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("superscript text within italic text within bold quote", func() { + source := "**some _italic and ^superscriptcontent^_**" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic and "}, + types.QuotedText{ + Kind: types.Superscript, + Elements: []interface{}{ + types.StringElement{Content: "superscriptcontent"}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + + Context("Quoted text inline", func() { + + It("inline content with bold text", func() { + source := "a paragraph with *some bold content*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some bold content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("inline content with invalid bold text - use case 1", func() { + source := "a paragraph with *some bold content" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with *some bold content"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("inline content with invalid bold text - use case 2", func() { + source := "a paragraph with *some bold content *" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with *some bold content *"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("inline content with invalid bold text - use case 3", func() { + source := "a paragraph with * some bold content*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with * some bold content*"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("invalid italic text within bold text", func() { + source := "some *bold and _italic content _ together*." + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold and _italic content _ together"}, + }, + }, + types.StringElement{Content: "."}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("italic text within invalid bold text", func() { + source := "some *bold and _italic content_ together *." + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "some *bold and "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic content"}, + }, + }, + types.StringElement{Content: " together *."}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("inline content with invalid subscript text - use case 1", func() { + source := "a paragraph with ~some subscript content" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with ~some subscript content"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("inline content with invalid subscript text - use case 2", func() { + source := "a paragraph with ~some subscript content ~" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with ~some subscript content ~"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("inline content with invalid subscript text - use case 3", func() { + source := "a paragraph with ~ some subscript content~" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with ~ some subscript content~"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("inline content with invalid superscript text - use case 1", func() { + source := "a paragraph with ^some superscript content" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.StringElement{Content: "a paragraph with ^some superscript content"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("inline content with invalid superscript text - use case 2", func() { + source := "a paragraph with ^some superscript content ^" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.StringElement{Content: "a paragraph with ^some superscript content ^"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("inline content with invalid superscript text - use case 3", func() { + source := "a paragraph with ^ some superscript content^" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.StringElement{Content: "a paragraph with ^ some superscript content^"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + + Context("nested quoted text", func() { + + It("italic text within bold text", func() { + source := "some *bold and _italic content_ together*." + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold and "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic content"}, + }, + }, + types.StringElement{Content: " together"}, + }, + }, + types.StringElement{Content: "."}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("single-quote bold within single-quote bold text", func() { + // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "*some *nested bold* content*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some *nested bold"}, + }, + }, + types.StringElement{Content: " content*"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("double-quote bold within double-quote bold text", func() { + // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "**some **nested bold** content**" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + }, + }, + types.StringElement{Content: "nested bold"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: " content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("single-quote bold within double-quote bold text", func() { + // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "**some *nested bold* content**" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "nested bold"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("double-quote bold within single-quote bold text", func() { + // here we don't allow for bold text within bold text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "*some **nested bold** content*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "nested bold"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("single-quote italic within single-quote italic text", func() { + // here we don't allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "_some _nested italic_ content_" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some _nested italic"}, + }, + }, + types.StringElement{Content: " content_"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("double-quote italic within double-quote italic text", func() { + // here we don't allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "__some __nested italic__ content__" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + }, + }, + types.StringElement{Content: "nested italic"}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: " content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("single-quote italic within double-quote italic text", func() { + // here we allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "_some __nested italic__ content_" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "nested italic"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("double-quote italic within single-quote italic text", func() { + // here we allow for italic text within italic text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "_some __nested italic__ content_" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "nested italic"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("single-quote monospace within single-quote monospace text", func() { + // here we don't allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "`some `nested monospace` content`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some `nested monospace"}, + }, + }, + types.StringElement{Content: " content`"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("double-quote monospace within double-quote monospace text", func() { + // here we don't allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "``some ``nested monospace`` content``" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + }, + }, + types.StringElement{Content: "nested monospace"}, + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: " content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("single-quote monospace within double-quote monospace text", func() { + // here we allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "`some ``nested monospace`` content`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "nested monospace"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("double-quote monospace within single-quote monospace text", func() { + // here we allow for monospace text within monospace text, to comply with the existing implementations (asciidoc and asciidoctor) + source := "`some ``nested monospace`` content`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some "}, + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "nested monospace"}, + }, + }, + types.StringElement{Content: " content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("unbalanced bold in monospace - case 1", func() { + source := "`*a`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "*a"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("unbalanced bold in monospace - case 2", func() { + source := "`a*b`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a*b"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("italic in monospace", func() { + source := "`_a_`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "a"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("unbalanced italic in monospace", func() { + source := "`a_b`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a_b"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("unparsed bold in monospace", func() { + source := "`a*b*`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a*b*"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("parsed subscript in monospace", func() { + source := "`a~b~`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a"}, + types.QuotedText{ + Kind: types.Subscript, + Elements: []interface{}{ + types.StringElement{Content: "b"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("multiline in single quoted monospace - case 1", func() { + source := "`a\nb`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a\nb"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("multiline in double quoted monospace - case 1", func() { + source := "`a\nb`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a\nb"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("multiline in single quoted monospace - case 2", func() { + source := "`a\n*b*`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a\n"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "b"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("multiline in double quoted monospace - case 2", func() { + source := "`a\n*b*`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a\n"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "b"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("link in bold", func() { + source := "*a link:/[b]*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineLink{ + Attributes: types.ElementAttributes{ + types.AttrInlineLinkText: []interface{}{ + types.StringElement{ + Content: "b", + }, + }, + }, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "/", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("image in bold", func() { + source := "*a image:foo.png[]*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineImage{ + Attributes: types.ElementAttributes{ + types.AttrImageAlt: "foo", + }, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "foo.png", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("singleplus passthrough in bold", func() { + source := "*a +image:foo.png[]+*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.SinglePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("tripleplus passthrough in bold", func() { + source := "*a +++image:foo.png[]+++*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.TriplePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("link in italic", func() { + source := "_a link:/[b]_" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineLink{ + Attributes: types.ElementAttributes{ + types.AttrInlineLinkText: []interface{}{ + types.StringElement{ + Content: "b", + }, + }, + }, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "/", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("image in italic", func() { + source := "_a image:foo.png[]_" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineImage{ + Attributes: types.ElementAttributes{ + types.AttrImageAlt: "foo", + }, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "foo.png", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("singleplus passthrough in italic", func() { + source := "_a +image:foo.png[]+_" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.SinglePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("tripleplus passthrough in italic", func() { + source := "_a +++image:foo.png[]+++_" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.TriplePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("link in monospace", func() { + source := "`a link:/[b]`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineLink{ + Attributes: types.ElementAttributes{ + types.AttrInlineLinkText: []interface{}{ + types.StringElement{ + Content: "b", + }, + }, + }, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "/", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("image in monospace", func() { + source := "`a image:foo.png[]`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.InlineImage{ + Attributes: types.ElementAttributes{ + types.AttrImageAlt: "foo", + }, + Location: types.Location{ + Elements: []interface{}{ + types.StringElement{ + Content: "foo.png", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("singleplus passthrough in monospace", func() { + source := "`a +image:foo.png[]+`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.SinglePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("tripleplus passthrough in monospace", func() { + source := "`a +++image:foo.png[]+++`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "a "}, + types.Passthrough{ + Kind: types.TriplePlusPassthrough, + Elements: []interface{}{ + types.StringElement{Content: "image:foo.png[]"}, + }, + }, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + }) + + Context("unbalanced quoted text", func() { + + Context("unbalanced bold text", func() { + + It("unbalanced bold text - extra on left", func() { + source := "**some bold content*" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "*some bold content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("unbalanced bold text - extra on right", func() { + source := "*some bold content**" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "some bold content"}, + }, + }, + types.StringElement{Content: "*"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + + Context("unbalanced italic text", func() { + + It("unbalanced italic text - extra on left", func() { + source := "__some italic content_" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "_some italic content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("unbalanced italic text - extra on right", func() { + source := "_some italic content__" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "some italic content"}, + }, + }, + types.StringElement{Content: "_"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + + Context("unbalanced monospace text", func() { + + It("unbalanced monospace text - extra on left", func() { + source := "``some monospace content`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "`some monospace content"}, + }, + }, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("unbalanced monospace text - extra on right", func() { + source := "`some monospace content``" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "some monospace content"}, + }, + }, + types.StringElement{Content: "`"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + + It("inline content with unbalanced bold text", func() { + source := "a paragraph with *some bold content" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "a paragraph with *some bold content"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + }) + + Context("prevented substitution", func() { + + Context("prevented bold text substitution", func() { + + Context("without nested quoted text", func() { + + It("escaped bold text with single backslash", func() { + source := `\*bold content*` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "*bold content*"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped bold text with multiple backslashes", func() { + source := `\\*bold content*` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\*bold content*`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped bold text with double quote", func() { + source := `\\**bold content**` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `**bold content**`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped bold text with double quote and more backslashes", func() { + source := `\\\**bold content**` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\**bold content**`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped bold text with unbalanced double quote", func() { + source := `\**bold content*` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `**bold content*`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped bold text with unbalanced double quote and more backslashes", func() { + source := `\\\**bold content*` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\\**bold content*`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + + Context("with nested quoted text", func() { + + It("escaped bold text with nested italic text", func() { + source := `\*_italic content_*` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "*"}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic content"}, + }, + }, + types.StringElement{Content: "*"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped bold text with unbalanced double quote and nested italic test", func() { + source := `\**_italic content_*` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "**"}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "italic content"}, + }, + }, + types.StringElement{Content: "*"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped bold text with nested italic", func() { + source := `\*bold _and italic_ content*` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "*bold "}, + types.QuotedText{ + Kind: types.Italic, + Elements: []interface{}{ + types.StringElement{Content: "and italic"}, + }, + }, + types.StringElement{Content: " content*"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + + }) + + Context("prevented italic text substitution", func() { + + Context("without nested quoted text", func() { + + It("escaped italic text with single quote", func() { + source := `\_italic content_` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "_italic content_"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped italic text with single quote and more backslashes", func() { + source := `\\_italic content_` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\_italic content_`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped italic text with double quote with 2 backslashes", func() { + source := `\\__italic content__` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `__italic content__`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped italic text with double quote with 3 backslashes", func() { + source := `\\\__italic content__` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\__italic content__`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped italic text with unbalanced double quote", func() { + source := `\__italic content_` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `__italic content_`}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped italic text with unbalanced double quote and more backslashes", func() { + source := `\\\__italic content_` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\\__italic content_`}, // only 1 backslash remove + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + + Context("with nested quoted text", func() { + + It("escaped italic text with nested monospace text", func() { + source := `\` + "_`monospace content`_" // gives: \_`monospace content`_ + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "_"}, + types.QuotedText{ + Kind: types.Monospace, + Elements: []interface{}{ + types.StringElement{Content: "monospace content"}, + }, + }, + types.StringElement{Content: "_"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped italic text with unbalanced double quote and nested bold test", func() { + source := `\__*bold content*_` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "__"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, + }, + types.StringElement{Content: "_"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped italic text with nested bold text", func() { + source := `\_italic *and bold* content_` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "_italic "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "and bold"}, + }, + }, + types.StringElement{Content: " content_"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + }) + + Context("prevented monospace text substitution", func() { + + Context("without nested quoted text", func() { + + It("escaped monospace text with single quote", func() { + source := `\` + "`monospace content`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "`monospace content`"}, // backslash removed + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped monospace text with single quote and more backslashes", func() { + source := `\\` + "`monospace content`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\` + "`monospace content`"}, // only 1 backslash removed + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped monospace text with double quote", func() { + source := `\\` + "`monospace content``" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\` + "`monospace content``"}, // 2 back slashes "consumed" + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped monospace text with double quote and more backslashes", func() { + source := `\\\` + "``monospace content``" // 3 backslashes + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\` + "``monospace content``"}, // 2 back slashes "consumed" + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped monospace text with unbalanced double quote", func() { + source := `\` + "``monospace content`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "``monospace content`"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped monospace text with unbalanced double quote and more backslashes", func() { + source := `\\\` + "``monospace content`" // 3 backslashes + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\\` + "``monospace content`"}, // 2 backslashes removed + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + + Context("with nested quoted text", func() { + + It("escaped monospace text with nested bold text", func() { + source := `\` + "`*bold content*`" // gives: \`*bold content*` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "`"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, + }, + types.StringElement{Content: "`"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped monospace text with unbalanced double backquote and nested bold test", func() { + source := `\` + "``*bold content*`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "``"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, + }, + types.StringElement{Content: "`"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped monospace text with nested bold text", func() { + source := `\` + "`monospace *and bold* content`" + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "`monospace "}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "and bold"}, + }, + }, + types.StringElement{Content: " content`"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + }) + + Context("prevented subscript text substitution", func() { + + Context("without nested quoted text", func() { + + It("escaped subscript text with single quote", func() { + source := `\~subscriptcontent~` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "~subscriptcontent~"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped subscript text with single quote and more backslashes", func() { + source := `\\~subscriptcontent~` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\~subscriptcontent~`}, // only 1 backslash removed + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + }) + + Context("with nested quoted text", func() { + + It("escaped subscript text with nested bold text", func() { + source := `\~*boldcontent*~` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "~"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "boldcontent"}, + }, + }, + types.StringElement{Content: "~"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped subscript text with nested bold text", func() { + source := `\~subscript *and bold* content~` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\~subscript `}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "and bold"}, + }, + }, + types.StringElement{Content: " content~"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + }) + }) + + Context("prevented superscript text substitution", func() { + + Context("without nested quoted text", func() { + + It("escaped superscript text with single quote", func() { + source := `\^superscriptcontent^` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "^superscriptcontent^"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped superscript text with single quote and more backslashes", func() { + source := `\\^superscriptcontent^` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\^superscriptcontent^`}, // only 1 backslash removed + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + }) + + Context("with nested quoted text", func() { + + It("escaped superscript text with nested bold text - case 1", func() { + source := `\^*bold content*^` // valid escaped superscript since it has no space within + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `^`}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, + }, + types.StringElement{Content: "^"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped superscript text with unbalanced double backquote and nested bold test", func() { + source := `\^*bold content*^` + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: "^"}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "bold content"}, + }, + }, + types.StringElement{Content: "^"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) + + It("escaped superscript text with nested bold text - case 2", func() { + source := `\^superscript *and bold* content^` // invalid superscript text since it has spaces within + expected := types.Document{ + Attributes: types.DocumentAttributes{}, + ElementReferences: types.ElementReferences{}, + Footnotes: types.Footnotes{}, + FootnoteReferences: types.FootnoteReferences{}, + Elements: []interface{}{ + types.Paragraph{ + Attributes: types.ElementAttributes{}, + Lines: [][]interface{}{ + { + types.StringElement{Content: `\^superscript `}, + types.QuotedText{ + Kind: types.Bold, + Elements: []interface{}{ + types.StringElement{Content: "and bold"}, + }, + }, + types.StringElement{Content: " content^"}, + }, + }, + }, + }, + } + Expect(source).To(BecomeDocument(expected)) + }) }) }) }) diff --git a/pkg/renderer/html5/delimited_block.go b/pkg/renderer/html5/delimited_block.go index 23298c9f..e82a62ec 100644 --- a/pkg/renderer/html5/delimited_block.go +++ b/pkg/renderer/html5/delimited_block.go @@ -151,8 +151,6 @@ func renderDelimitedBlock(ctx *renderer.Context, b types.DelimitedBlock) ([]byte return renderVerseBlock(ctx, b) case types.Sidebar: return renderSidebarBlock(ctx, b) - case types.Comment: - return renderCommentBlock(ctx, b) default: return nil, errors.Wrapf(err, "unable to render delimited block") } @@ -338,11 +336,6 @@ func renderVerseBlockParagraph(ctx *renderer.Context, p types.Paragraph) ([]byte return result.Bytes(), err } -func renderCommentBlock(ctx *renderer.Context, b types.DelimitedBlock) ([]byte, error) { //nolint: unparam - // comments block are not preserved during rendering - return []byte{}, nil -} - func renderSidebarBlock(ctx *renderer.Context, b types.DelimitedBlock) ([]byte, error) { result := bytes.NewBuffer(nil) err := sidebarBlockTmpl.Execute(result, ContextualPipeline{ diff --git a/pkg/renderer/html5/html5.go b/pkg/renderer/html5/html5.go index dc222618..2e9f1cc4 100644 --- a/pkg/renderer/html5/html5.go +++ b/pkg/renderer/html5/html5.go @@ -127,8 +127,6 @@ func renderElement(ctx *renderer.Context, element interface{}) ([]byte, error) { return renderLineBreak() case types.UserMacro: return renderUserMacro(ctx, e) - case types.SingleLineComment: - return nil, nil // nothing to do default: return nil, errors.Errorf("unsupported type of element: %T", element) } diff --git a/pkg/renderer/html5/paragraph.go b/pkg/renderer/html5/paragraph.go index 58b5ee6f..ec6b9cec 100644 --- a/pkg/renderer/html5/paragraph.go +++ b/pkg/renderer/html5/paragraph.go @@ -21,10 +21,10 @@ var quoteParagraphTmpl texttemplate.Template // initializes the templates func init() { paragraphTmpl = newTextTemplate("paragraph", - `{{ $ctx := .Context }}{{ with .Data }}{{ $renderedLines := renderLines $ctx .Lines .HardBreaks | printf "%s" }}{{ if ne $renderedLines "" }}
{{ if ne .Title "" }} + `{{ $ctx := .Context }}{{ with .Data }}{{ $renderedLines := renderLines $ctx .Lines .HardBreaks | printf "%s" }}
{{ if ne .Title "" }}
{{ escape .Title }}
{{ end }}

{{ $renderedLines }}

-
{{ end }}{{ end }}`, +
{{ end }}`, texttemplate.FuncMap{ "renderLines": renderLines, "escape": EscapeString, @@ -98,9 +98,9 @@ func init() { } func renderParagraph(ctx *renderer.Context, p types.Paragraph) ([]byte, error) { - if len(p.Lines) == 0 { - return make([]byte, 0), nil - } + // if len(p.Lines) == 0 { + // return make([]byte, 0), nil + // } result := bytes.NewBuffer(nil) id := renderElementID(p.Attributes) var err error diff --git a/pkg/renderer/html5/paragraph_test.go b/pkg/renderer/html5/paragraph_test.go index 8ceaf0d8..dd7b976f 100644 --- a/pkg/renderer/html5/paragraph_test.go +++ b/pkg/renderer/html5/paragraph_test.go @@ -65,6 +65,15 @@ and here another paragraph ` Expect(source).To(RenderHTML5Body(expected)) }) + + It("empty paragraph", func() { + source := `{blank}` + expected := `
+

+
` + Expect(source).To(RenderHTML5Body(expected)) + + }) }) Context("paragraphs with line break", func() { diff --git a/pkg/renderer/html5/passthrough_test.go b/pkg/renderer/html5/passthrough_test.go index 96203039..b9f65c6f 100644 --- a/pkg/renderer/html5/passthrough_test.go +++ b/pkg/renderer/html5/passthrough_test.go @@ -12,8 +12,11 @@ var _ = Describe("passthroughs", func() { Context("tripleplus passthrough", func() { It("an empty standalone tripleplus passthrough", func() { + // here it differs from Asciidoctor which returns no content but reports an error ("unterminated pass block") source := `++++++` - expected := `` + expected := `
+

+
` Expect(source).To(RenderHTML5Body(expected)) }) @@ -105,7 +108,9 @@ var _ = Describe("passthroughs", func() { It("empty passthrough macro", func() { source := `pass:[]` - expected := `` + expected := `
+

+
` Expect(source).To(RenderHTML5Body(expected)) }) diff --git a/pkg/types/element_attributes.go b/pkg/types/element_attributes.go index 0832c5da..92dabc65 100644 --- a/pkg/types/element_attributes.go +++ b/pkg/types/element_attributes.go @@ -29,9 +29,9 @@ const ( // AttrRevision the key to the revision declared after the section level 0 (at the beginning of the doc) AttrRevision string = "revision" // AttrTableOfContents the `toc` attribute at document level - AttrTableOfContents = "toc" + AttrTableOfContents string = "toc" // AttrTableOfContentsLevels the document attribute which specifies the number of levels to display in the ToC - AttrTableOfContentsLevels = "toclevels" + AttrTableOfContentsLevels string = "toclevels" // AttrRole the key to retrieve the role in the element attributes AttrRole string = "role" // AttrInlineLink the key to retrieve the link in the element attributes @@ -51,17 +51,25 @@ const ( // AttrStart the `start` attribute in an ordered list AttrStart string = "start" // AttrNumberingStyle the numbering style of items in a list - AttrNumberingStyle = "numberingStyle" + AttrNumberingStyle string = "numberingStyle" // AttrQandA the `qanda` attribute for Q&A labeled lists AttrQandA string = "qanda" // AttrLevelOffset the `leveloffset` attribute used in file inclusions - AttrLevelOffset = "leveloffset" + AttrLevelOffset string = "leveloffset" // AttrLineRanges the `lines` attribute used in file inclusions - AttrLineRanges = "lines" + AttrLineRanges string = "lines" // AttrTagRanges the `tag`/`tags` attribute used in file inclusions - AttrTagRanges = "tags" + AttrTagRanges string = "tags" // AttrLastUpdated the "last updated" data in the document, i.e., the output/generation time - AttrLastUpdated = "LastUpdated" + AttrLastUpdated string = "LastUpdated" + // AttrImageAlt the image `alt` attribute + AttrImageAlt string = "alt" + // AttrImageWidth the image `width` attribute + AttrImageWidth string = "width" + // AttrImageHeight the image `height` attribute + AttrImageHeight string = "height" + // AttrImageTitle the image `title` attribute + AttrImageTitle string = "title" ) // ElementWithAttributes an element on which attributes can be added/set diff --git a/pkg/types/types.go b/pkg/types/types.go index bf11ae48..66e986a2 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -468,7 +468,7 @@ type List interface { } // ListItem a list item -type ListItem interface { +type ListItem interface { // TODO: convert to struct and use as composant in OrderedListItem, etc. AddElement(interface{}) } @@ -973,6 +973,7 @@ const ( func NewInlineElements(elements ...interface{}) ([]interface{}, error) { result := MergeStringElements(elements...) return result, nil + } // ------------------------------------------ @@ -1002,17 +1003,6 @@ func NewCrossReference(id string, label interface{}) (CrossReference, error) { // Images // ------------------------------------------ -const ( - // AttrImageAlt the image `alt` attribute - AttrImageAlt string = "alt" - // AttrImageWidth the image `width` attribute - AttrImageWidth string = "width" - // AttrImageHeight the image `height` attribute - AttrImageHeight string = "height" - // AttrImageTitle the image `title` attribute - AttrImageTitle string = "title" -) - // ImageBlock the structure for the block images type ImageBlock struct { Location Location @@ -1336,7 +1326,7 @@ type SingleLineComment struct { // NewSingleLineComment initializes a new single line content func NewSingleLineComment(content string) (SingleLineComment, error) { - // log.Debugf("initializing a single line comment with content: '%s'", content) + log.Debugf("initializing a single line comment with content: '%s'", content) return SingleLineComment{ Content: content, }, nil diff --git a/pkg/types/types_utils.go b/pkg/types/types_utils.go index 16a2099a..b7f1a825 100644 --- a/pkg/types/types_utils.go +++ b/pkg/types/types_utils.go @@ -4,63 +4,8 @@ import ( "bytes" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" ) -// FilterCriterion returns true if the given element is to be filtered out -type FilterCriterion func(element interface{}) bool - -// EmptyPreambleMatcher filters the element if it is an empty preamble -var EmptyPreambleMatcher FilterCriterion = func(element interface{}) bool { - result := false - if p, match := element.(Preamble); match { - result = p.Elements == nil || len(p.Elements) == 0 - } - log.Debugf(" element of type '%T' is an empty preamble: %t", element, result) - return result -} - -// BlankLineMatcher filters the element if it is a blank line -var BlankLineMatcher FilterCriterion = func(element interface{}) bool { - _, result := element.(BlankLine) - return result -} - -// DocumentAttributeMatcher filters the element if it is a blank line -var DocumentAttributeMatcher FilterCriterion = func(element interface{}) bool { - switch element.(type) { - case DocumentAttributeDeclaration, DocumentAttributeSubstitution, DocumentAttributeReset: - return true - default: - return false - } -} - -// FilterOut excludes the unrelevant (empty) elements -func FilterOut(elements []interface{}, filters ...FilterCriterion) []interface{} { - log.Debugf("filtering %d blocks...", len(elements)) - result := make([]interface{}, 0) -blocks: - for _, element := range elements { - // check if filter option applies to the element - switch element := element.(type) { - case []interface{}: - result = append(result, FilterOut(element, filters...)...) - default: - for _, filter := range filters { - if filter(element) { - log.Debugf("discarding block of type '%T'", element) - continue blocks - } - } - log.Debugf("keeping block of type '%T'", element) - result = append(result, element) - continue - } - } - return result -} - // NilSafe returns a new slice if the given elements is nil, otherwise it returns the given elements func NilSafe(elements []interface{}) []interface{} { if elements != nil { diff --git a/pkg/types/types_utils_test.go b/pkg/types/types_utils_test.go index 6692838b..9a6046e3 100644 --- a/pkg/types/types_utils_test.go +++ b/pkg/types/types_utils_test.go @@ -34,49 +34,3 @@ var _ = Describe("convert to inline elements", func() { Expect(result).To(Equal(expected)) }) }) - -var _ = Describe("filter elements", func() { - - It("filter elements with all options", func() { - // given - source := []interface{}{ - BlankLine{}, - Preamble{}, - StringElement{ - Content: "foo", - }, - Preamble{ - Elements: []interface{}{ - StringElement{ - Content: "bar", - }, - }, - }, - []interface{}{ - BlankLine{}, - StringElement{ - Content: "baz", - }, - }, - } - // when - result := FilterOut(source, BlankLineMatcher, EmptyPreambleMatcher) - // then - expected := []interface{}{ - StringElement{ - Content: "foo", - }, - Preamble{ - Elements: []interface{}{ - StringElement{ - Content: "bar", - }, - }, - }, - StringElement{ - Content: "baz", - }, - } - Expect(result).To(Equal(expected)) - }) -})