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)) - }) -})