From 65f9c9c19063f56b03e5a07c76a2cf4389833143 Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Sun, 7 Jan 2018 15:10:50 +0100 Subject: [PATCH] feat(parser/renderer): support cross-references with Element ID (#47) Signed-off-by: Xavier Coulon --- parser/asciidoc-grammar.peg | 28 +- parser/asciidoc_parser.go | 1489 +++++++++++++----------- parser/asciidoc_parser_test.go | 10 + parser/blank_line_test.go | 6 +- parser/cross_reference_test.go | 28 + parser/delimited_block_test.go | 30 +- parser/document_attributes_test.go | 41 +- parser/element_attributes_test.go | 149 +++ parser/external_link_test.go | 68 +- parser/frontmatter_test.go | 4 +- parser/image_test.go | 281 ++--- parser/list_test.go | 548 ++++----- parser/literal_block_test.go | 32 +- parser/meta_elements_test.go | 137 --- parser/paragraph_test.go | 79 +- parser/quoted_text_test.go | 120 +- parser/section_test.go | 149 ++- parser/table_of_contents_test.go | 24 + renderer/html5/cross_reference.go | 48 + renderer/html5/cross_reference_test.go | 47 + renderer/html5/renderer.go | 20 +- renderer/html5/section.go | 5 +- types/document_xrefs.go | 40 + types/grammar_types.go | 129 +- types/grammar_types_utils.go | 133 +-- types/non_alphanumerics_replacement.go | 130 +++ 26 files changed, 2095 insertions(+), 1680 deletions(-) create mode 100644 parser/cross_reference_test.go create mode 100644 parser/element_attributes_test.go delete mode 100644 parser/meta_elements_test.go create mode 100644 renderer/html5/cross_reference.go create mode 100644 renderer/html5/cross_reference_test.go create mode 100644 types/document_xrefs.go create mode 100644 types/non_alphanumerics_replacement.go diff --git a/parser/asciidoc-grammar.peg b/parser/asciidoc-grammar.peg index 631dffcf..e4e5b983 100644 --- a/parser/asciidoc-grammar.peg +++ b/parser/asciidoc-grammar.peg @@ -225,7 +225,7 @@ InlineContent <- !BlockDelimiter elements:(WS* InlineElement WS*)+ &EOL { // nee return types.NewInlineContent(elements.([]interface{})) } -InlineElement <- Passthrough / InlineImage / QuotedText / ExternalLink / DocumentAttributeSubstitution / Characters +InlineElement <- CrossReference / Passthrough / InlineImage / QuotedText / ExternalLink / DocumentAttributeSubstitution / Characters // ---------------------------------------------------------------------------- // Quoted Texts (bold, italic and monospace) including substitution prevention @@ -328,6 +328,7 @@ QuotedTextContent <- QuotedTextContentElement (WS+ QuotedTextContentElement)* QuotedTextContentElement <- QuotedText / QuotedTextCharacters / CharactersWithQuotePunctuation // word with quote punctuation is only accepted if nothing matched before, so we have a chance to stop QuotedTextCharacters <- (!NEWLINE !WS !"*" !"_" !"`" .)+ // cannot have "*", "_" or "`" within + CharactersWithQuotePunctuation <- (!NEWLINE !WS .)+ { // can have "*", "_" or "`" within, maybe because the user inserted another quote, or made an error (extra or missing space, for example) return c.text, nil } @@ -335,7 +336,6 @@ CharactersWithQuotePunctuation <- (!NEWLINE !WS .)+ { // can have "*", "_" or " // make sure unbalanced punctuation for quoted text is treated accordingly UnbalancedQuotePunctuation <- "*" / "_" / "`" - // ------------------------------------------ // Passthrough // ------------------------------------------ @@ -361,6 +361,13 @@ PassthroughWithQuotedText <- "pass:q[" content:(QuotedText / PassthroughMacroCha PassthroughMacroCharacter <- (!"]" .) +// ------------------------------------------ +// Cross References +// ------------------------------------------ +CrossReference <- "<<" id:(ID) ">>" { + return types.NewCrossReference(id.(string)) +} + // ------------------------------------------ // Links // ------------------------------------------ @@ -448,15 +455,20 @@ ParagraphWithLiteralAttribute <- "[literal]" WS* NEWLINE content:(LiteralBlockCo // ------------------------------------------ // Element Attributes // ------------------------------------------ -ElementAttribute <- meta:(ElementLink / ElementID / ElementTitle) +ElementAttribute <- ElementLink / ElementID / ElementTitle / InvalidElementAttribute // a link attached to an element, such as a BlockImage -ElementLink <- "[" WS* "link" WS* "=" WS* path:URL WS* "]" EOL { +ElementLink <- "[link=" WS* path:URL WS* "]" EOL { return types.NewElementLink(path.(string)) } +ElementID <- ElementIDNormal / ElementIDShortHand + // an id attached to an element, such as a BlockImage -ElementID <- "[" WS* "#" id:(ID) WS* "]" EOL { +ElementIDNormal <- "[[" id:(ID) "]]" EOL { + return types.NewElementID(id.(string)) +} +ElementIDShortHand <- "[#" id:(ID) "]" EOL { return types.NewElementID(id.(string)) } @@ -466,6 +478,10 @@ ElementTitle <- "." !"." !WS title:(!NEWLINE .)+ EOL { return types.NewElementTitle(title.([]interface{})) } +InvalidElementAttribute <- "[" WS+ content:(!"]" .)* "]" { + return types.NewInvalidElementAttribute(c.text) +} + // ------------------------------------------ // BlankLine // ------------------------------------------ @@ -485,7 +501,7 @@ URL <- (!NEWLINE !WS !"[" !"]" .)+ { return string(c.text), nil } -ID <- (!NEWLINE !WS !"[" !"]" .)+ { +ID <- (!NEWLINE !WS !"[" !"]" !"<<" !">>".)+ { return string(c.text), nil } diff --git a/parser/asciidoc_parser.go b/parser/asciidoc_parser.go index aa571479..86ca5108 100644 --- a/parser/asciidoc_parser.go +++ b/parser/asciidoc_parser.go @@ -2384,26 +2384,30 @@ var g = &grammar{ alternatives: []interface{}{ &ruleRefExpr{ pos: position{line: 228, col: 18, offset: 9499}, + name: "CrossReference", + }, + &ruleRefExpr{ + pos: position{line: 228, col: 35, offset: 9516}, name: "Passthrough", }, &ruleRefExpr{ - pos: position{line: 228, col: 32, offset: 9513}, + pos: position{line: 228, col: 49, offset: 9530}, name: "InlineImage", }, &ruleRefExpr{ - pos: position{line: 228, col: 46, offset: 9527}, + pos: position{line: 228, col: 63, offset: 9544}, name: "QuotedText", }, &ruleRefExpr{ - pos: position{line: 228, col: 59, offset: 9540}, + pos: position{line: 228, col: 76, offset: 9557}, name: "ExternalLink", }, &ruleRefExpr{ - pos: position{line: 228, col: 74, offset: 9555}, + pos: position{line: 228, col: 91, offset: 9572}, name: "DocumentAttributeSubstitution", }, &ruleRefExpr{ - pos: position{line: 228, col: 106, offset: 9587}, + pos: position{line: 228, col: 123, offset: 9604}, name: "Characters", }, }, @@ -2411,32 +2415,32 @@ var g = &grammar{ }, { name: "QuotedText", - pos: position{line: 233, col: 1, offset: 9838}, + pos: position{line: 233, col: 1, offset: 9855}, expr: &choiceExpr{ - pos: position{line: 233, col: 15, offset: 9852}, + pos: position{line: 233, col: 15, offset: 9869}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 233, col: 15, offset: 9852}, + pos: position{line: 233, col: 15, offset: 9869}, name: "BoldText", }, &ruleRefExpr{ - pos: position{line: 233, col: 26, offset: 9863}, + pos: position{line: 233, col: 26, offset: 9880}, name: "ItalicText", }, &ruleRefExpr{ - pos: position{line: 233, col: 39, offset: 9876}, + pos: position{line: 233, col: 39, offset: 9893}, name: "MonospaceText", }, &ruleRefExpr{ - pos: position{line: 234, col: 13, offset: 9904}, + pos: position{line: 234, col: 13, offset: 9921}, name: "EscapedBoldText", }, &ruleRefExpr{ - pos: position{line: 234, col: 31, offset: 9922}, + pos: position{line: 234, col: 31, offset: 9939}, name: "EscapedItalicText", }, &ruleRefExpr{ - pos: position{line: 234, col: 51, offset: 9942}, + pos: position{line: 234, col: 51, offset: 9959}, name: "EscapedMonospaceText", }, }, @@ -2444,20 +2448,20 @@ var g = &grammar{ }, { name: "BoldText", - pos: position{line: 236, col: 1, offset: 9964}, + pos: position{line: 236, col: 1, offset: 9981}, expr: &choiceExpr{ - pos: position{line: 236, col: 13, offset: 9976}, + pos: position{line: 236, col: 13, offset: 9993}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 236, col: 13, offset: 9976}, + pos: position{line: 236, col: 13, offset: 9993}, name: "BoldTextDoublePunctuation", }, &ruleRefExpr{ - pos: position{line: 236, col: 41, offset: 10004}, + pos: position{line: 236, col: 41, offset: 10021}, name: "BoldTextUnbalancedPunctuation", }, &ruleRefExpr{ - pos: position{line: 236, col: 73, offset: 10036}, + pos: position{line: 236, col: 73, offset: 10053}, name: "BoldTextSimplePunctuation", }, }, @@ -2465,36 +2469,36 @@ var g = &grammar{ }, { name: "BoldTextSimplePunctuation", - pos: position{line: 238, col: 1, offset: 10109}, + pos: position{line: 238, col: 1, offset: 10126}, expr: &actionExpr{ - pos: position{line: 238, col: 30, offset: 10138}, + pos: position{line: 238, col: 30, offset: 10155}, run: (*parser).callonBoldTextSimplePunctuation1, expr: &seqExpr{ - pos: position{line: 238, col: 30, offset: 10138}, + pos: position{line: 238, col: 30, offset: 10155}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 238, col: 30, offset: 10138}, + pos: position{line: 238, col: 30, offset: 10155}, expr: &litMatcher{ - pos: position{line: 238, col: 31, offset: 10139}, + pos: position{line: 238, col: 31, offset: 10156}, val: "\\", ignoreCase: false, }, }, &litMatcher{ - pos: position{line: 238, col: 35, offset: 10143}, + pos: position{line: 238, col: 35, offset: 10160}, val: "*", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 238, col: 39, offset: 10147}, + pos: position{line: 238, col: 39, offset: 10164}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 238, col: 48, offset: 10156}, + pos: position{line: 238, col: 48, offset: 10173}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 238, col: 67, offset: 10175}, + pos: position{line: 238, col: 67, offset: 10192}, val: "*", ignoreCase: false, }, @@ -2504,36 +2508,36 @@ var g = &grammar{ }, { name: "BoldTextDoublePunctuation", - pos: position{line: 242, col: 1, offset: 10252}, + pos: position{line: 242, col: 1, offset: 10269}, expr: &actionExpr{ - pos: position{line: 242, col: 30, offset: 10281}, + pos: position{line: 242, col: 30, offset: 10298}, run: (*parser).callonBoldTextDoublePunctuation1, expr: &seqExpr{ - pos: position{line: 242, col: 30, offset: 10281}, + pos: position{line: 242, col: 30, offset: 10298}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 242, col: 30, offset: 10281}, + pos: position{line: 242, col: 30, offset: 10298}, expr: &litMatcher{ - pos: position{line: 242, col: 31, offset: 10282}, + pos: position{line: 242, col: 31, offset: 10299}, val: "\\\\", ignoreCase: false, }, }, &litMatcher{ - pos: position{line: 242, col: 36, offset: 10287}, + pos: position{line: 242, col: 36, offset: 10304}, val: "**", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 242, col: 41, offset: 10292}, + pos: position{line: 242, col: 41, offset: 10309}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 242, col: 50, offset: 10301}, + pos: position{line: 242, col: 50, offset: 10318}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 242, col: 69, offset: 10320}, + pos: position{line: 242, col: 69, offset: 10337}, val: "**", ignoreCase: false, }, @@ -2543,36 +2547,36 @@ var g = &grammar{ }, { name: "BoldTextUnbalancedPunctuation", - pos: position{line: 246, col: 1, offset: 10398}, + pos: position{line: 246, col: 1, offset: 10415}, expr: &actionExpr{ - pos: position{line: 246, col: 34, offset: 10431}, + pos: position{line: 246, col: 34, offset: 10448}, run: (*parser).callonBoldTextUnbalancedPunctuation1, expr: &seqExpr{ - pos: position{line: 246, col: 34, offset: 10431}, + pos: position{line: 246, col: 34, offset: 10448}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 246, col: 34, offset: 10431}, + pos: position{line: 246, col: 34, offset: 10448}, expr: &litMatcher{ - pos: position{line: 246, col: 35, offset: 10432}, + pos: position{line: 246, col: 35, offset: 10449}, val: "\\\\", ignoreCase: false, }, }, &litMatcher{ - pos: position{line: 246, col: 40, offset: 10437}, + pos: position{line: 246, col: 40, offset: 10454}, val: "**", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 246, col: 45, offset: 10442}, + pos: position{line: 246, col: 45, offset: 10459}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 246, col: 54, offset: 10451}, + pos: position{line: 246, col: 54, offset: 10468}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 246, col: 73, offset: 10470}, + pos: position{line: 246, col: 73, offset: 10487}, val: "*", ignoreCase: false, }, @@ -2582,20 +2586,20 @@ var g = &grammar{ }, { name: "EscapedBoldText", - pos: position{line: 251, col: 1, offset: 10634}, + pos: position{line: 251, col: 1, offset: 10651}, expr: &choiceExpr{ - pos: position{line: 251, col: 20, offset: 10653}, + pos: position{line: 251, col: 20, offset: 10670}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 251, col: 20, offset: 10653}, + pos: position{line: 251, col: 20, offset: 10670}, name: "EscapedBoldTextDoublePunctuation", }, &ruleRefExpr{ - pos: position{line: 251, col: 55, offset: 10688}, + pos: position{line: 251, col: 55, offset: 10705}, name: "EscapedBoldTextUnbalancedPunctuation", }, &ruleRefExpr{ - pos: position{line: 251, col: 94, offset: 10727}, + pos: position{line: 251, col: 94, offset: 10744}, name: "EscapedBoldTextSimplePunctuation", }, }, @@ -2603,28 +2607,28 @@ var g = &grammar{ }, { name: "EscapedBoldTextSimplePunctuation", - pos: position{line: 253, col: 1, offset: 10807}, + pos: position{line: 253, col: 1, offset: 10824}, expr: &actionExpr{ - pos: position{line: 253, col: 37, offset: 10843}, + pos: position{line: 253, col: 37, offset: 10860}, run: (*parser).callonEscapedBoldTextSimplePunctuation1, expr: &seqExpr{ - pos: position{line: 253, col: 37, offset: 10843}, + pos: position{line: 253, col: 37, offset: 10860}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 253, col: 37, offset: 10843}, + pos: position{line: 253, col: 37, offset: 10860}, label: "backslashes", expr: &seqExpr{ - pos: position{line: 253, col: 50, offset: 10856}, + pos: position{line: 253, col: 50, offset: 10873}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 253, col: 50, offset: 10856}, + pos: position{line: 253, col: 50, offset: 10873}, val: "\\", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 253, col: 54, offset: 10860}, + pos: position{line: 253, col: 54, offset: 10877}, expr: &litMatcher{ - pos: position{line: 253, col: 54, offset: 10860}, + pos: position{line: 253, col: 54, offset: 10877}, val: "\\", ignoreCase: false, }, @@ -2633,20 +2637,20 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 253, col: 60, offset: 10866}, + pos: position{line: 253, col: 60, offset: 10883}, val: "*", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 253, col: 64, offset: 10870}, + pos: position{line: 253, col: 64, offset: 10887}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 253, col: 73, offset: 10879}, + pos: position{line: 253, col: 73, offset: 10896}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 253, col: 92, offset: 10898}, + pos: position{line: 253, col: 92, offset: 10915}, val: "*", ignoreCase: false, }, @@ -2656,28 +2660,28 @@ var g = &grammar{ }, { name: "EscapedBoldTextDoublePunctuation", - pos: position{line: 257, col: 1, offset: 11004}, + pos: position{line: 257, col: 1, offset: 11021}, expr: &actionExpr{ - pos: position{line: 257, col: 37, offset: 11040}, + pos: position{line: 257, col: 37, offset: 11057}, run: (*parser).callonEscapedBoldTextDoublePunctuation1, expr: &seqExpr{ - pos: position{line: 257, col: 37, offset: 11040}, + pos: position{line: 257, col: 37, offset: 11057}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 257, col: 37, offset: 11040}, + pos: position{line: 257, col: 37, offset: 11057}, label: "backslashes", expr: &seqExpr{ - pos: position{line: 257, col: 50, offset: 11053}, + pos: position{line: 257, col: 50, offset: 11070}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 257, col: 50, offset: 11053}, + pos: position{line: 257, col: 50, offset: 11070}, val: "\\\\", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 257, col: 55, offset: 11058}, + pos: position{line: 257, col: 55, offset: 11075}, expr: &litMatcher{ - pos: position{line: 257, col: 55, offset: 11058}, + pos: position{line: 257, col: 55, offset: 11075}, val: "\\", ignoreCase: false, }, @@ -2686,20 +2690,20 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 257, col: 61, offset: 11064}, + pos: position{line: 257, col: 61, offset: 11081}, val: "**", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 257, col: 66, offset: 11069}, + pos: position{line: 257, col: 66, offset: 11086}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 257, col: 75, offset: 11078}, + pos: position{line: 257, col: 75, offset: 11095}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 257, col: 94, offset: 11097}, + pos: position{line: 257, col: 94, offset: 11114}, val: "**", ignoreCase: false, }, @@ -2709,28 +2713,28 @@ var g = &grammar{ }, { name: "EscapedBoldTextUnbalancedPunctuation", - pos: position{line: 261, col: 1, offset: 11205}, + pos: position{line: 261, col: 1, offset: 11222}, expr: &actionExpr{ - pos: position{line: 261, col: 42, offset: 11246}, + pos: position{line: 261, col: 42, offset: 11263}, run: (*parser).callonEscapedBoldTextUnbalancedPunctuation1, expr: &seqExpr{ - pos: position{line: 261, col: 42, offset: 11246}, + pos: position{line: 261, col: 42, offset: 11263}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 261, col: 42, offset: 11246}, + pos: position{line: 261, col: 42, offset: 11263}, label: "backslashes", expr: &seqExpr{ - pos: position{line: 261, col: 55, offset: 11259}, + pos: position{line: 261, col: 55, offset: 11276}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 261, col: 55, offset: 11259}, + pos: position{line: 261, col: 55, offset: 11276}, val: "\\", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 261, col: 59, offset: 11263}, + pos: position{line: 261, col: 59, offset: 11280}, expr: &litMatcher{ - pos: position{line: 261, col: 59, offset: 11263}, + pos: position{line: 261, col: 59, offset: 11280}, val: "\\", ignoreCase: false, }, @@ -2739,20 +2743,20 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 261, col: 65, offset: 11269}, + pos: position{line: 261, col: 65, offset: 11286}, val: "**", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 261, col: 70, offset: 11274}, + pos: position{line: 261, col: 70, offset: 11291}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 261, col: 79, offset: 11283}, + pos: position{line: 261, col: 79, offset: 11300}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 261, col: 98, offset: 11302}, + pos: position{line: 261, col: 98, offset: 11319}, val: "*", ignoreCase: false, }, @@ -2762,20 +2766,20 @@ var g = &grammar{ }, { name: "ItalicText", - pos: position{line: 266, col: 1, offset: 11495}, + pos: position{line: 266, col: 1, offset: 11512}, expr: &choiceExpr{ - pos: position{line: 266, col: 15, offset: 11509}, + pos: position{line: 266, col: 15, offset: 11526}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 266, col: 15, offset: 11509}, + pos: position{line: 266, col: 15, offset: 11526}, name: "ItalicTextDoublePunctuation", }, &ruleRefExpr{ - pos: position{line: 266, col: 45, offset: 11539}, + pos: position{line: 266, col: 45, offset: 11556}, name: "ItalicTextUnbalancedPunctuation", }, &ruleRefExpr{ - pos: position{line: 266, col: 79, offset: 11573}, + pos: position{line: 266, col: 79, offset: 11590}, name: "ItalicTextSimplePunctuation", }, }, @@ -2783,36 +2787,36 @@ var g = &grammar{ }, { name: "ItalicTextSimplePunctuation", - pos: position{line: 268, col: 1, offset: 11602}, + pos: position{line: 268, col: 1, offset: 11619}, expr: &actionExpr{ - pos: position{line: 268, col: 32, offset: 11633}, + pos: position{line: 268, col: 32, offset: 11650}, run: (*parser).callonItalicTextSimplePunctuation1, expr: &seqExpr{ - pos: position{line: 268, col: 32, offset: 11633}, + pos: position{line: 268, col: 32, offset: 11650}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 268, col: 32, offset: 11633}, + pos: position{line: 268, col: 32, offset: 11650}, expr: &litMatcher{ - pos: position{line: 268, col: 33, offset: 11634}, + pos: position{line: 268, col: 33, offset: 11651}, val: "\\", ignoreCase: false, }, }, &litMatcher{ - pos: position{line: 268, col: 37, offset: 11638}, + pos: position{line: 268, col: 37, offset: 11655}, val: "_", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 268, col: 41, offset: 11642}, + pos: position{line: 268, col: 41, offset: 11659}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 268, col: 50, offset: 11651}, + pos: position{line: 268, col: 50, offset: 11668}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 268, col: 69, offset: 11670}, + pos: position{line: 268, col: 69, offset: 11687}, val: "_", ignoreCase: false, }, @@ -2822,36 +2826,36 @@ var g = &grammar{ }, { name: "ItalicTextDoublePunctuation", - pos: position{line: 272, col: 1, offset: 11749}, + pos: position{line: 272, col: 1, offset: 11766}, expr: &actionExpr{ - pos: position{line: 272, col: 32, offset: 11780}, + pos: position{line: 272, col: 32, offset: 11797}, run: (*parser).callonItalicTextDoublePunctuation1, expr: &seqExpr{ - pos: position{line: 272, col: 32, offset: 11780}, + pos: position{line: 272, col: 32, offset: 11797}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 272, col: 32, offset: 11780}, + pos: position{line: 272, col: 32, offset: 11797}, expr: &litMatcher{ - pos: position{line: 272, col: 33, offset: 11781}, + pos: position{line: 272, col: 33, offset: 11798}, val: "\\\\", ignoreCase: false, }, }, &litMatcher{ - pos: position{line: 272, col: 38, offset: 11786}, + pos: position{line: 272, col: 38, offset: 11803}, val: "__", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 272, col: 43, offset: 11791}, + pos: position{line: 272, col: 43, offset: 11808}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 272, col: 52, offset: 11800}, + pos: position{line: 272, col: 52, offset: 11817}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 272, col: 71, offset: 11819}, + pos: position{line: 272, col: 71, offset: 11836}, val: "__", ignoreCase: false, }, @@ -2861,36 +2865,36 @@ var g = &grammar{ }, { name: "ItalicTextUnbalancedPunctuation", - pos: position{line: 276, col: 1, offset: 11899}, + pos: position{line: 276, col: 1, offset: 11916}, expr: &actionExpr{ - pos: position{line: 276, col: 36, offset: 11934}, + pos: position{line: 276, col: 36, offset: 11951}, run: (*parser).callonItalicTextUnbalancedPunctuation1, expr: &seqExpr{ - pos: position{line: 276, col: 36, offset: 11934}, + pos: position{line: 276, col: 36, offset: 11951}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 276, col: 36, offset: 11934}, + pos: position{line: 276, col: 36, offset: 11951}, expr: &litMatcher{ - pos: position{line: 276, col: 37, offset: 11935}, + pos: position{line: 276, col: 37, offset: 11952}, val: "\\\\", ignoreCase: false, }, }, &litMatcher{ - pos: position{line: 276, col: 42, offset: 11940}, + pos: position{line: 276, col: 42, offset: 11957}, val: "__", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 276, col: 47, offset: 11945}, + pos: position{line: 276, col: 47, offset: 11962}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 276, col: 56, offset: 11954}, + pos: position{line: 276, col: 56, offset: 11971}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 276, col: 75, offset: 11973}, + pos: position{line: 276, col: 75, offset: 11990}, val: "_", ignoreCase: false, }, @@ -2900,20 +2904,20 @@ var g = &grammar{ }, { name: "EscapedItalicText", - pos: position{line: 281, col: 1, offset: 12139}, + pos: position{line: 281, col: 1, offset: 12156}, expr: &choiceExpr{ - pos: position{line: 281, col: 22, offset: 12160}, + pos: position{line: 281, col: 22, offset: 12177}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 281, col: 22, offset: 12160}, + pos: position{line: 281, col: 22, offset: 12177}, name: "EscapedItalicTextDoublePunctuation", }, &ruleRefExpr{ - pos: position{line: 281, col: 59, offset: 12197}, + pos: position{line: 281, col: 59, offset: 12214}, name: "EscapedItalicTextUnbalancedPunctuation", }, &ruleRefExpr{ - pos: position{line: 281, col: 100, offset: 12238}, + pos: position{line: 281, col: 100, offset: 12255}, name: "EscapedItalicTextSimplePunctuation", }, }, @@ -2921,28 +2925,28 @@ var g = &grammar{ }, { name: "EscapedItalicTextSimplePunctuation", - pos: position{line: 283, col: 1, offset: 12320}, + pos: position{line: 283, col: 1, offset: 12337}, expr: &actionExpr{ - pos: position{line: 283, col: 39, offset: 12358}, + pos: position{line: 283, col: 39, offset: 12375}, run: (*parser).callonEscapedItalicTextSimplePunctuation1, expr: &seqExpr{ - pos: position{line: 283, col: 39, offset: 12358}, + pos: position{line: 283, col: 39, offset: 12375}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 283, col: 39, offset: 12358}, + pos: position{line: 283, col: 39, offset: 12375}, label: "backslashes", expr: &seqExpr{ - pos: position{line: 283, col: 52, offset: 12371}, + pos: position{line: 283, col: 52, offset: 12388}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 283, col: 52, offset: 12371}, + pos: position{line: 283, col: 52, offset: 12388}, val: "\\", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 283, col: 56, offset: 12375}, + pos: position{line: 283, col: 56, offset: 12392}, expr: &litMatcher{ - pos: position{line: 283, col: 56, offset: 12375}, + pos: position{line: 283, col: 56, offset: 12392}, val: "\\", ignoreCase: false, }, @@ -2951,20 +2955,20 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 283, col: 62, offset: 12381}, + pos: position{line: 283, col: 62, offset: 12398}, val: "_", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 283, col: 66, offset: 12385}, + pos: position{line: 283, col: 66, offset: 12402}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 283, col: 75, offset: 12394}, + pos: position{line: 283, col: 75, offset: 12411}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 283, col: 94, offset: 12413}, + pos: position{line: 283, col: 94, offset: 12430}, val: "_", ignoreCase: false, }, @@ -2974,28 +2978,28 @@ var g = &grammar{ }, { name: "EscapedItalicTextDoublePunctuation", - pos: position{line: 287, col: 1, offset: 12519}, + pos: position{line: 287, col: 1, offset: 12536}, expr: &actionExpr{ - pos: position{line: 287, col: 39, offset: 12557}, + pos: position{line: 287, col: 39, offset: 12574}, run: (*parser).callonEscapedItalicTextDoublePunctuation1, expr: &seqExpr{ - pos: position{line: 287, col: 39, offset: 12557}, + pos: position{line: 287, col: 39, offset: 12574}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 287, col: 39, offset: 12557}, + pos: position{line: 287, col: 39, offset: 12574}, label: "backslashes", expr: &seqExpr{ - pos: position{line: 287, col: 52, offset: 12570}, + pos: position{line: 287, col: 52, offset: 12587}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 287, col: 52, offset: 12570}, + pos: position{line: 287, col: 52, offset: 12587}, val: "\\\\", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 287, col: 57, offset: 12575}, + pos: position{line: 287, col: 57, offset: 12592}, expr: &litMatcher{ - pos: position{line: 287, col: 57, offset: 12575}, + pos: position{line: 287, col: 57, offset: 12592}, val: "\\", ignoreCase: false, }, @@ -3004,20 +3008,20 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 287, col: 63, offset: 12581}, + pos: position{line: 287, col: 63, offset: 12598}, val: "__", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 287, col: 68, offset: 12586}, + pos: position{line: 287, col: 68, offset: 12603}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 287, col: 77, offset: 12595}, + pos: position{line: 287, col: 77, offset: 12612}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 287, col: 96, offset: 12614}, + pos: position{line: 287, col: 96, offset: 12631}, val: "__", ignoreCase: false, }, @@ -3027,28 +3031,28 @@ var g = &grammar{ }, { name: "EscapedItalicTextUnbalancedPunctuation", - pos: position{line: 291, col: 1, offset: 12722}, + pos: position{line: 291, col: 1, offset: 12739}, expr: &actionExpr{ - pos: position{line: 291, col: 44, offset: 12765}, + pos: position{line: 291, col: 44, offset: 12782}, run: (*parser).callonEscapedItalicTextUnbalancedPunctuation1, expr: &seqExpr{ - pos: position{line: 291, col: 44, offset: 12765}, + pos: position{line: 291, col: 44, offset: 12782}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 291, col: 44, offset: 12765}, + pos: position{line: 291, col: 44, offset: 12782}, label: "backslashes", expr: &seqExpr{ - pos: position{line: 291, col: 57, offset: 12778}, + pos: position{line: 291, col: 57, offset: 12795}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 291, col: 57, offset: 12778}, + pos: position{line: 291, col: 57, offset: 12795}, val: "\\", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 291, col: 61, offset: 12782}, + pos: position{line: 291, col: 61, offset: 12799}, expr: &litMatcher{ - pos: position{line: 291, col: 61, offset: 12782}, + pos: position{line: 291, col: 61, offset: 12799}, val: "\\", ignoreCase: false, }, @@ -3057,20 +3061,20 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 291, col: 67, offset: 12788}, + pos: position{line: 291, col: 67, offset: 12805}, val: "__", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 291, col: 72, offset: 12793}, + pos: position{line: 291, col: 72, offset: 12810}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 291, col: 81, offset: 12802}, + pos: position{line: 291, col: 81, offset: 12819}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 291, col: 100, offset: 12821}, + pos: position{line: 291, col: 100, offset: 12838}, val: "_", ignoreCase: false, }, @@ -3080,20 +3084,20 @@ var g = &grammar{ }, { name: "MonospaceText", - pos: position{line: 296, col: 1, offset: 13014}, + pos: position{line: 296, col: 1, offset: 13031}, expr: &choiceExpr{ - pos: position{line: 296, col: 18, offset: 13031}, + pos: position{line: 296, col: 18, offset: 13048}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 296, col: 18, offset: 13031}, + pos: position{line: 296, col: 18, offset: 13048}, name: "MonospaceTextDoublePunctuation", }, &ruleRefExpr{ - pos: position{line: 296, col: 51, offset: 13064}, + pos: position{line: 296, col: 51, offset: 13081}, name: "MonospaceTextUnbalancedPunctuation", }, &ruleRefExpr{ - pos: position{line: 296, col: 88, offset: 13101}, + pos: position{line: 296, col: 88, offset: 13118}, name: "MonospaceTextSimplePunctuation", }, }, @@ -3101,36 +3105,36 @@ var g = &grammar{ }, { name: "MonospaceTextSimplePunctuation", - pos: position{line: 298, col: 1, offset: 13133}, + pos: position{line: 298, col: 1, offset: 13150}, expr: &actionExpr{ - pos: position{line: 298, col: 35, offset: 13167}, + pos: position{line: 298, col: 35, offset: 13184}, run: (*parser).callonMonospaceTextSimplePunctuation1, expr: &seqExpr{ - pos: position{line: 298, col: 35, offset: 13167}, + pos: position{line: 298, col: 35, offset: 13184}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 298, col: 35, offset: 13167}, + pos: position{line: 298, col: 35, offset: 13184}, expr: &litMatcher{ - pos: position{line: 298, col: 36, offset: 13168}, + pos: position{line: 298, col: 36, offset: 13185}, val: "\\", ignoreCase: false, }, }, &litMatcher{ - pos: position{line: 298, col: 40, offset: 13172}, + pos: position{line: 298, col: 40, offset: 13189}, val: "`", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 298, col: 44, offset: 13176}, + pos: position{line: 298, col: 44, offset: 13193}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 298, col: 53, offset: 13185}, + pos: position{line: 298, col: 53, offset: 13202}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 298, col: 72, offset: 13204}, + pos: position{line: 298, col: 72, offset: 13221}, val: "`", ignoreCase: false, }, @@ -3140,36 +3144,36 @@ var g = &grammar{ }, { name: "MonospaceTextDoublePunctuation", - pos: position{line: 302, col: 1, offset: 13286}, + pos: position{line: 302, col: 1, offset: 13303}, expr: &actionExpr{ - pos: position{line: 302, col: 35, offset: 13320}, + pos: position{line: 302, col: 35, offset: 13337}, run: (*parser).callonMonospaceTextDoublePunctuation1, expr: &seqExpr{ - pos: position{line: 302, col: 35, offset: 13320}, + pos: position{line: 302, col: 35, offset: 13337}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 302, col: 35, offset: 13320}, + pos: position{line: 302, col: 35, offset: 13337}, expr: &litMatcher{ - pos: position{line: 302, col: 36, offset: 13321}, + pos: position{line: 302, col: 36, offset: 13338}, val: "\\\\", ignoreCase: false, }, }, &litMatcher{ - pos: position{line: 302, col: 41, offset: 13326}, + pos: position{line: 302, col: 41, offset: 13343}, val: "``", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 302, col: 46, offset: 13331}, + pos: position{line: 302, col: 46, offset: 13348}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 302, col: 55, offset: 13340}, + pos: position{line: 302, col: 55, offset: 13357}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 302, col: 74, offset: 13359}, + pos: position{line: 302, col: 74, offset: 13376}, val: "``", ignoreCase: false, }, @@ -3179,36 +3183,36 @@ var g = &grammar{ }, { name: "MonospaceTextUnbalancedPunctuation", - pos: position{line: 306, col: 1, offset: 13442}, + pos: position{line: 306, col: 1, offset: 13459}, expr: &actionExpr{ - pos: position{line: 306, col: 39, offset: 13480}, + pos: position{line: 306, col: 39, offset: 13497}, run: (*parser).callonMonospaceTextUnbalancedPunctuation1, expr: &seqExpr{ - pos: position{line: 306, col: 39, offset: 13480}, + pos: position{line: 306, col: 39, offset: 13497}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 306, col: 39, offset: 13480}, + pos: position{line: 306, col: 39, offset: 13497}, expr: &litMatcher{ - pos: position{line: 306, col: 40, offset: 13481}, + pos: position{line: 306, col: 40, offset: 13498}, val: "\\\\", ignoreCase: false, }, }, &litMatcher{ - pos: position{line: 306, col: 45, offset: 13486}, + pos: position{line: 306, col: 45, offset: 13503}, val: "``", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 306, col: 50, offset: 13491}, + pos: position{line: 306, col: 50, offset: 13508}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 306, col: 59, offset: 13500}, + pos: position{line: 306, col: 59, offset: 13517}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 306, col: 78, offset: 13519}, + pos: position{line: 306, col: 78, offset: 13536}, val: "`", ignoreCase: false, }, @@ -3218,20 +3222,20 @@ var g = &grammar{ }, { name: "EscapedMonospaceText", - pos: position{line: 311, col: 1, offset: 13688}, + pos: position{line: 311, col: 1, offset: 13705}, expr: &choiceExpr{ - pos: position{line: 311, col: 25, offset: 13712}, + pos: position{line: 311, col: 25, offset: 13729}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 311, col: 25, offset: 13712}, + pos: position{line: 311, col: 25, offset: 13729}, name: "EscapedMonospaceTextDoublePunctuation", }, &ruleRefExpr{ - pos: position{line: 311, col: 65, offset: 13752}, + pos: position{line: 311, col: 65, offset: 13769}, name: "EscapedMonospaceTextUnbalancedPunctuation", }, &ruleRefExpr{ - pos: position{line: 311, col: 109, offset: 13796}, + pos: position{line: 311, col: 109, offset: 13813}, name: "EscapedMonospaceTextSimplePunctuation", }, }, @@ -3239,28 +3243,28 @@ var g = &grammar{ }, { name: "EscapedMonospaceTextSimplePunctuation", - pos: position{line: 313, col: 1, offset: 13881}, + pos: position{line: 313, col: 1, offset: 13898}, expr: &actionExpr{ - pos: position{line: 313, col: 42, offset: 13922}, + pos: position{line: 313, col: 42, offset: 13939}, run: (*parser).callonEscapedMonospaceTextSimplePunctuation1, expr: &seqExpr{ - pos: position{line: 313, col: 42, offset: 13922}, + pos: position{line: 313, col: 42, offset: 13939}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 313, col: 42, offset: 13922}, + pos: position{line: 313, col: 42, offset: 13939}, label: "backslashes", expr: &seqExpr{ - pos: position{line: 313, col: 55, offset: 13935}, + pos: position{line: 313, col: 55, offset: 13952}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 313, col: 55, offset: 13935}, + pos: position{line: 313, col: 55, offset: 13952}, val: "\\", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 313, col: 59, offset: 13939}, + pos: position{line: 313, col: 59, offset: 13956}, expr: &litMatcher{ - pos: position{line: 313, col: 59, offset: 13939}, + pos: position{line: 313, col: 59, offset: 13956}, val: "\\", ignoreCase: false, }, @@ -3269,20 +3273,20 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 313, col: 65, offset: 13945}, + pos: position{line: 313, col: 65, offset: 13962}, val: "`", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 313, col: 69, offset: 13949}, + pos: position{line: 313, col: 69, offset: 13966}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 313, col: 78, offset: 13958}, + pos: position{line: 313, col: 78, offset: 13975}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 313, col: 97, offset: 13977}, + pos: position{line: 313, col: 97, offset: 13994}, val: "`", ignoreCase: false, }, @@ -3292,28 +3296,28 @@ var g = &grammar{ }, { name: "EscapedMonospaceTextDoublePunctuation", - pos: position{line: 317, col: 1, offset: 14083}, + pos: position{line: 317, col: 1, offset: 14100}, expr: &actionExpr{ - pos: position{line: 317, col: 42, offset: 14124}, + pos: position{line: 317, col: 42, offset: 14141}, run: (*parser).callonEscapedMonospaceTextDoublePunctuation1, expr: &seqExpr{ - pos: position{line: 317, col: 42, offset: 14124}, + pos: position{line: 317, col: 42, offset: 14141}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 317, col: 42, offset: 14124}, + pos: position{line: 317, col: 42, offset: 14141}, label: "backslashes", expr: &seqExpr{ - pos: position{line: 317, col: 55, offset: 14137}, + pos: position{line: 317, col: 55, offset: 14154}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 317, col: 55, offset: 14137}, + pos: position{line: 317, col: 55, offset: 14154}, val: "\\\\", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 317, col: 60, offset: 14142}, + pos: position{line: 317, col: 60, offset: 14159}, expr: &litMatcher{ - pos: position{line: 317, col: 60, offset: 14142}, + pos: position{line: 317, col: 60, offset: 14159}, val: "\\", ignoreCase: false, }, @@ -3322,20 +3326,20 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 317, col: 66, offset: 14148}, + pos: position{line: 317, col: 66, offset: 14165}, val: "``", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 317, col: 71, offset: 14153}, + pos: position{line: 317, col: 71, offset: 14170}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 317, col: 80, offset: 14162}, + pos: position{line: 317, col: 80, offset: 14179}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 317, col: 99, offset: 14181}, + pos: position{line: 317, col: 99, offset: 14198}, val: "``", ignoreCase: false, }, @@ -3345,28 +3349,28 @@ var g = &grammar{ }, { name: "EscapedMonospaceTextUnbalancedPunctuation", - pos: position{line: 321, col: 1, offset: 14289}, + pos: position{line: 321, col: 1, offset: 14306}, expr: &actionExpr{ - pos: position{line: 321, col: 47, offset: 14335}, + pos: position{line: 321, col: 47, offset: 14352}, run: (*parser).callonEscapedMonospaceTextUnbalancedPunctuation1, expr: &seqExpr{ - pos: position{line: 321, col: 47, offset: 14335}, + pos: position{line: 321, col: 47, offset: 14352}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 321, col: 47, offset: 14335}, + pos: position{line: 321, col: 47, offset: 14352}, label: "backslashes", expr: &seqExpr{ - pos: position{line: 321, col: 60, offset: 14348}, + pos: position{line: 321, col: 60, offset: 14365}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 321, col: 60, offset: 14348}, + pos: position{line: 321, col: 60, offset: 14365}, val: "\\", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 321, col: 64, offset: 14352}, + pos: position{line: 321, col: 64, offset: 14369}, expr: &litMatcher{ - pos: position{line: 321, col: 64, offset: 14352}, + pos: position{line: 321, col: 64, offset: 14369}, val: "\\", ignoreCase: false, }, @@ -3375,20 +3379,20 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 321, col: 70, offset: 14358}, + pos: position{line: 321, col: 70, offset: 14375}, val: "``", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 321, col: 75, offset: 14363}, + pos: position{line: 321, col: 75, offset: 14380}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 321, col: 84, offset: 14372}, + pos: position{line: 321, col: 84, offset: 14389}, name: "QuotedTextContent", }, }, &litMatcher{ - pos: position{line: 321, col: 103, offset: 14391}, + pos: position{line: 321, col: 103, offset: 14408}, val: "`", ignoreCase: false, }, @@ -3398,28 +3402,28 @@ var g = &grammar{ }, { name: "QuotedTextContent", - pos: position{line: 326, col: 1, offset: 14584}, + pos: position{line: 326, col: 1, offset: 14601}, expr: &seqExpr{ - pos: position{line: 326, col: 22, offset: 14605}, + pos: position{line: 326, col: 22, offset: 14622}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 326, col: 22, offset: 14605}, + pos: position{line: 326, col: 22, offset: 14622}, name: "QuotedTextContentElement", }, &zeroOrMoreExpr{ - pos: position{line: 326, col: 47, offset: 14630}, + pos: position{line: 326, col: 47, offset: 14647}, expr: &seqExpr{ - pos: position{line: 326, col: 48, offset: 14631}, + pos: position{line: 326, col: 48, offset: 14648}, exprs: []interface{}{ &oneOrMoreExpr{ - pos: position{line: 326, col: 48, offset: 14631}, + pos: position{line: 326, col: 48, offset: 14648}, expr: &ruleRefExpr{ - pos: position{line: 326, col: 48, offset: 14631}, + pos: position{line: 326, col: 48, offset: 14648}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 326, col: 52, offset: 14635}, + pos: position{line: 326, col: 52, offset: 14652}, name: "QuotedTextContentElement", }, }, @@ -3430,20 +3434,20 @@ var g = &grammar{ }, { name: "QuotedTextContentElement", - pos: position{line: 328, col: 1, offset: 14663}, + pos: position{line: 328, col: 1, offset: 14680}, expr: &choiceExpr{ - pos: position{line: 328, col: 29, offset: 14691}, + pos: position{line: 328, col: 29, offset: 14708}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 328, col: 29, offset: 14691}, + pos: position{line: 328, col: 29, offset: 14708}, name: "QuotedText", }, &ruleRefExpr{ - pos: position{line: 328, col: 42, offset: 14704}, + pos: position{line: 328, col: 42, offset: 14721}, name: "QuotedTextCharacters", }, &ruleRefExpr{ - pos: position{line: 328, col: 65, offset: 14727}, + pos: position{line: 328, col: 65, offset: 14744}, name: "CharactersWithQuotePunctuation", }, }, @@ -3451,52 +3455,52 @@ var g = &grammar{ }, { name: "QuotedTextCharacters", - pos: position{line: 330, col: 1, offset: 14862}, + pos: position{line: 330, col: 1, offset: 14879}, expr: &oneOrMoreExpr{ - pos: position{line: 330, col: 25, offset: 14886}, + pos: position{line: 330, col: 25, offset: 14903}, expr: &seqExpr{ - pos: position{line: 330, col: 26, offset: 14887}, + pos: position{line: 330, col: 26, offset: 14904}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 330, col: 26, offset: 14887}, + pos: position{line: 330, col: 26, offset: 14904}, expr: &ruleRefExpr{ - pos: position{line: 330, col: 27, offset: 14888}, + pos: position{line: 330, col: 27, offset: 14905}, name: "NEWLINE", }, }, ¬Expr{ - pos: position{line: 330, col: 35, offset: 14896}, + pos: position{line: 330, col: 35, offset: 14913}, expr: &ruleRefExpr{ - pos: position{line: 330, col: 36, offset: 14897}, + pos: position{line: 330, col: 36, offset: 14914}, name: "WS", }, }, ¬Expr{ - pos: position{line: 330, col: 39, offset: 14900}, + pos: position{line: 330, col: 39, offset: 14917}, expr: &litMatcher{ - pos: position{line: 330, col: 40, offset: 14901}, + pos: position{line: 330, col: 40, offset: 14918}, val: "*", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 330, col: 44, offset: 14905}, + pos: position{line: 330, col: 44, offset: 14922}, expr: &litMatcher{ - pos: position{line: 330, col: 45, offset: 14906}, + pos: position{line: 330, col: 45, offset: 14923}, val: "_", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 330, col: 49, offset: 14910}, + pos: position{line: 330, col: 49, offset: 14927}, expr: &litMatcher{ - pos: position{line: 330, col: 50, offset: 14911}, + pos: position{line: 330, col: 50, offset: 14928}, val: "`", ignoreCase: false, }, }, &anyMatcher{ - line: 330, col: 54, offset: 14915, + line: 330, col: 54, offset: 14932, }, }, }, @@ -3504,31 +3508,31 @@ var g = &grammar{ }, { name: "CharactersWithQuotePunctuation", - pos: position{line: 331, col: 1, offset: 14957}, + pos: position{line: 332, col: 1, offset: 14975}, expr: &actionExpr{ - pos: position{line: 331, col: 35, offset: 14991}, + pos: position{line: 332, col: 35, offset: 15009}, run: (*parser).callonCharactersWithQuotePunctuation1, expr: &oneOrMoreExpr{ - pos: position{line: 331, col: 35, offset: 14991}, + pos: position{line: 332, col: 35, offset: 15009}, expr: &seqExpr{ - pos: position{line: 331, col: 36, offset: 14992}, + pos: position{line: 332, col: 36, offset: 15010}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 331, col: 36, offset: 14992}, + pos: position{line: 332, col: 36, offset: 15010}, expr: &ruleRefExpr{ - pos: position{line: 331, col: 37, offset: 14993}, + pos: position{line: 332, col: 37, offset: 15011}, name: "NEWLINE", }, }, ¬Expr{ - pos: position{line: 331, col: 45, offset: 15001}, + pos: position{line: 332, col: 45, offset: 15019}, expr: &ruleRefExpr{ - pos: position{line: 331, col: 46, offset: 15002}, + pos: position{line: 332, col: 46, offset: 15020}, name: "WS", }, }, &anyMatcher{ - line: 331, col: 50, offset: 15006, + line: 332, col: 50, offset: 15024, }, }, }, @@ -3537,22 +3541,22 @@ var g = &grammar{ }, { name: "UnbalancedQuotePunctuation", - pos: position{line: 336, col: 1, offset: 15251}, + pos: position{line: 337, col: 1, offset: 15269}, expr: &choiceExpr{ - pos: position{line: 336, col: 31, offset: 15281}, + pos: position{line: 337, col: 31, offset: 15299}, alternatives: []interface{}{ &litMatcher{ - pos: position{line: 336, col: 31, offset: 15281}, + pos: position{line: 337, col: 31, offset: 15299}, val: "*", ignoreCase: false, }, &litMatcher{ - pos: position{line: 336, col: 37, offset: 15287}, + pos: position{line: 337, col: 37, offset: 15305}, val: "_", ignoreCase: false, }, &litMatcher{ - pos: position{line: 336, col: 43, offset: 15293}, + pos: position{line: 337, col: 43, offset: 15311}, val: "`", ignoreCase: false, }, @@ -3561,20 +3565,20 @@ var g = &grammar{ }, { name: "Passthrough", - pos: position{line: 342, col: 1, offset: 15406}, + pos: position{line: 342, col: 1, offset: 15423}, expr: &choiceExpr{ - pos: position{line: 342, col: 16, offset: 15421}, + pos: position{line: 342, col: 16, offset: 15438}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 342, col: 16, offset: 15421}, + pos: position{line: 342, col: 16, offset: 15438}, name: "TriplePlusPassthrough", }, &ruleRefExpr{ - pos: position{line: 342, col: 40, offset: 15445}, + pos: position{line: 342, col: 40, offset: 15462}, name: "SinglePlusPassthrough", }, &ruleRefExpr{ - pos: position{line: 342, col: 64, offset: 15469}, + pos: position{line: 342, col: 64, offset: 15486}, name: "PassthroughMacro", }, }, @@ -3582,50 +3586,50 @@ var g = &grammar{ }, { name: "SinglePlusPassthrough", - pos: position{line: 344, col: 1, offset: 15487}, + pos: position{line: 344, col: 1, offset: 15504}, expr: &actionExpr{ - pos: position{line: 344, col: 26, offset: 15512}, + pos: position{line: 344, col: 26, offset: 15529}, run: (*parser).callonSinglePlusPassthrough1, expr: &seqExpr{ - pos: position{line: 344, col: 26, offset: 15512}, + pos: position{line: 344, col: 26, offset: 15529}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 344, col: 26, offset: 15512}, + pos: position{line: 344, col: 26, offset: 15529}, val: "+", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 344, col: 30, offset: 15516}, + pos: position{line: 344, col: 30, offset: 15533}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 344, col: 38, offset: 15524}, + pos: position{line: 344, col: 38, offset: 15541}, expr: &seqExpr{ - pos: position{line: 344, col: 39, offset: 15525}, + pos: position{line: 344, col: 39, offset: 15542}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 344, col: 39, offset: 15525}, + pos: position{line: 344, col: 39, offset: 15542}, expr: &ruleRefExpr{ - pos: position{line: 344, col: 40, offset: 15526}, + pos: position{line: 344, col: 40, offset: 15543}, name: "NEWLINE", }, }, ¬Expr{ - pos: position{line: 344, col: 48, offset: 15534}, + pos: position{line: 344, col: 48, offset: 15551}, expr: &litMatcher{ - pos: position{line: 344, col: 49, offset: 15535}, + pos: position{line: 344, col: 49, offset: 15552}, val: "+", ignoreCase: false, }, }, &anyMatcher{ - line: 344, col: 53, offset: 15539, + line: 344, col: 53, offset: 15556, }, }, }, }, }, &litMatcher{ - pos: position{line: 344, col: 57, offset: 15543}, + pos: position{line: 344, col: 57, offset: 15560}, val: "+", ignoreCase: false, }, @@ -3635,43 +3639,43 @@ var g = &grammar{ }, { name: "TriplePlusPassthrough", - pos: position{line: 348, col: 1, offset: 15638}, + pos: position{line: 348, col: 1, offset: 15655}, expr: &actionExpr{ - pos: position{line: 348, col: 26, offset: 15663}, + pos: position{line: 348, col: 26, offset: 15680}, run: (*parser).callonTriplePlusPassthrough1, expr: &seqExpr{ - pos: position{line: 348, col: 26, offset: 15663}, + pos: position{line: 348, col: 26, offset: 15680}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 348, col: 26, offset: 15663}, + pos: position{line: 348, col: 26, offset: 15680}, val: "+++", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 348, col: 32, offset: 15669}, + pos: position{line: 348, col: 32, offset: 15686}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 348, col: 40, offset: 15677}, + pos: position{line: 348, col: 40, offset: 15694}, expr: &seqExpr{ - pos: position{line: 348, col: 41, offset: 15678}, + pos: position{line: 348, col: 41, offset: 15695}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 348, col: 41, offset: 15678}, + pos: position{line: 348, col: 41, offset: 15695}, expr: &litMatcher{ - pos: position{line: 348, col: 42, offset: 15679}, + pos: position{line: 348, col: 42, offset: 15696}, val: "+++", ignoreCase: false, }, }, &anyMatcher{ - line: 348, col: 48, offset: 15685, + line: 348, col: 48, offset: 15702, }, }, }, }, }, &litMatcher{ - pos: position{line: 348, col: 52, offset: 15689}, + pos: position{line: 348, col: 52, offset: 15706}, val: "+++", ignoreCase: false, }, @@ -3681,16 +3685,16 @@ var g = &grammar{ }, { name: "PassthroughMacro", - pos: position{line: 352, col: 1, offset: 15786}, + pos: position{line: 352, col: 1, offset: 15803}, expr: &choiceExpr{ - pos: position{line: 352, col: 21, offset: 15806}, + pos: position{line: 352, col: 21, offset: 15823}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 352, col: 21, offset: 15806}, + pos: position{line: 352, col: 21, offset: 15823}, name: "SimplePassthroughMacro", }, &ruleRefExpr{ - pos: position{line: 352, col: 46, offset: 15831}, + pos: position{line: 352, col: 46, offset: 15848}, name: "PassthroughWithQuotedText", }, }, @@ -3698,31 +3702,31 @@ var g = &grammar{ }, { name: "SimplePassthroughMacro", - pos: position{line: 354, col: 1, offset: 15858}, + pos: position{line: 354, col: 1, offset: 15875}, expr: &actionExpr{ - pos: position{line: 354, col: 27, offset: 15884}, + pos: position{line: 354, col: 27, offset: 15901}, run: (*parser).callonSimplePassthroughMacro1, expr: &seqExpr{ - pos: position{line: 354, col: 27, offset: 15884}, + pos: position{line: 354, col: 27, offset: 15901}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 354, col: 27, offset: 15884}, + pos: position{line: 354, col: 27, offset: 15901}, val: "pass:[", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 354, col: 36, offset: 15893}, + pos: position{line: 354, col: 36, offset: 15910}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 354, col: 44, offset: 15901}, + pos: position{line: 354, col: 44, offset: 15918}, expr: &ruleRefExpr{ - pos: position{line: 354, col: 45, offset: 15902}, + pos: position{line: 354, col: 45, offset: 15919}, name: "PassthroughMacroCharacter", }, }, }, &litMatcher{ - pos: position{line: 354, col: 73, offset: 15930}, + pos: position{line: 354, col: 73, offset: 15947}, val: "]", ignoreCase: false, }, @@ -3732,32 +3736,32 @@ var g = &grammar{ }, { name: "PassthroughWithQuotedText", - pos: position{line: 358, col: 1, offset: 16020}, + pos: position{line: 358, col: 1, offset: 16037}, expr: &actionExpr{ - pos: position{line: 358, col: 30, offset: 16049}, + pos: position{line: 358, col: 30, offset: 16066}, run: (*parser).callonPassthroughWithQuotedText1, expr: &seqExpr{ - pos: position{line: 358, col: 30, offset: 16049}, + pos: position{line: 358, col: 30, offset: 16066}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 358, col: 30, offset: 16049}, + pos: position{line: 358, col: 30, offset: 16066}, val: "pass:q[", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 358, col: 40, offset: 16059}, + pos: position{line: 358, col: 40, offset: 16076}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 358, col: 48, offset: 16067}, + pos: position{line: 358, col: 48, offset: 16084}, expr: &choiceExpr{ - pos: position{line: 358, col: 49, offset: 16068}, + pos: position{line: 358, col: 49, offset: 16085}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 358, col: 49, offset: 16068}, + pos: position{line: 358, col: 49, offset: 16085}, name: "QuotedText", }, &ruleRefExpr{ - pos: position{line: 358, col: 62, offset: 16081}, + pos: position{line: 358, col: 62, offset: 16098}, name: "PassthroughMacroCharacter", }, }, @@ -3765,7 +3769,7 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 358, col: 90, offset: 16109}, + pos: position{line: 358, col: 90, offset: 16126}, val: "]", ignoreCase: false, }, @@ -3775,72 +3779,103 @@ var g = &grammar{ }, { name: "PassthroughMacroCharacter", - pos: position{line: 362, col: 1, offset: 16199}, + pos: position{line: 362, col: 1, offset: 16216}, expr: &seqExpr{ - pos: position{line: 362, col: 31, offset: 16229}, + pos: position{line: 362, col: 31, offset: 16246}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 362, col: 31, offset: 16229}, + pos: position{line: 362, col: 31, offset: 16246}, expr: &litMatcher{ - pos: position{line: 362, col: 32, offset: 16230}, + pos: position{line: 362, col: 32, offset: 16247}, val: "]", ignoreCase: false, }, }, &anyMatcher{ - line: 362, col: 36, offset: 16234, + line: 362, col: 36, offset: 16251, + }, + }, + }, + }, + { + name: "CrossReference", + pos: position{line: 367, col: 1, offset: 16367}, + expr: &actionExpr{ + pos: position{line: 367, col: 19, offset: 16385}, + run: (*parser).callonCrossReference1, + expr: &seqExpr{ + pos: position{line: 367, col: 19, offset: 16385}, + exprs: []interface{}{ + &litMatcher{ + pos: position{line: 367, col: 19, offset: 16385}, + val: "<<", + ignoreCase: false, + }, + &labeledExpr{ + pos: position{line: 367, col: 24, offset: 16390}, + label: "id", + expr: &ruleRefExpr{ + pos: position{line: 367, col: 28, offset: 16394}, + name: "ID", + }, + }, + &litMatcher{ + pos: position{line: 367, col: 32, offset: 16398}, + val: ">>", + ignoreCase: false, + }, }, }, }, }, { name: "ExternalLink", - pos: position{line: 367, col: 1, offset: 16339}, + pos: position{line: 374, col: 1, offset: 16557}, expr: &actionExpr{ - pos: position{line: 367, col: 17, offset: 16355}, + pos: position{line: 374, col: 17, offset: 16573}, run: (*parser).callonExternalLink1, expr: &seqExpr{ - pos: position{line: 367, col: 17, offset: 16355}, + pos: position{line: 374, col: 17, offset: 16573}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 367, col: 17, offset: 16355}, + pos: position{line: 374, col: 17, offset: 16573}, label: "url", expr: &seqExpr{ - pos: position{line: 367, col: 22, offset: 16360}, + pos: position{line: 374, col: 22, offset: 16578}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 367, col: 22, offset: 16360}, + pos: position{line: 374, col: 22, offset: 16578}, name: "URL_SCHEME", }, &ruleRefExpr{ - pos: position{line: 367, col: 33, offset: 16371}, + pos: position{line: 374, col: 33, offset: 16589}, name: "URL", }, }, }, }, &labeledExpr{ - pos: position{line: 367, col: 38, offset: 16376}, + pos: position{line: 374, col: 38, offset: 16594}, label: "text", expr: &zeroOrOneExpr{ - pos: position{line: 367, col: 43, offset: 16381}, + pos: position{line: 374, col: 43, offset: 16599}, expr: &seqExpr{ - pos: position{line: 367, col: 44, offset: 16382}, + pos: position{line: 374, col: 44, offset: 16600}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 367, col: 44, offset: 16382}, + pos: position{line: 374, col: 44, offset: 16600}, val: "[", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 367, col: 48, offset: 16386}, + pos: position{line: 374, col: 48, offset: 16604}, expr: &ruleRefExpr{ - pos: position{line: 367, col: 49, offset: 16387}, + pos: position{line: 374, col: 49, offset: 16605}, name: "URL_TEXT", }, }, &litMatcher{ - pos: position{line: 367, col: 60, offset: 16398}, + pos: position{line: 374, col: 60, offset: 16616}, val: "]", ignoreCase: false, }, @@ -3854,41 +3889,41 @@ var g = &grammar{ }, { name: "BlockImage", - pos: position{line: 377, col: 1, offset: 16677}, + pos: position{line: 384, col: 1, offset: 16895}, expr: &actionExpr{ - pos: position{line: 377, col: 15, offset: 16691}, + pos: position{line: 384, col: 15, offset: 16909}, run: (*parser).callonBlockImage1, expr: &seqExpr{ - pos: position{line: 377, col: 15, offset: 16691}, + pos: position{line: 384, col: 15, offset: 16909}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 377, col: 15, offset: 16691}, + pos: position{line: 384, col: 15, offset: 16909}, label: "attributes", expr: &zeroOrMoreExpr{ - pos: position{line: 377, col: 26, offset: 16702}, + pos: position{line: 384, col: 26, offset: 16920}, expr: &ruleRefExpr{ - pos: position{line: 377, col: 27, offset: 16703}, + pos: position{line: 384, col: 27, offset: 16921}, name: "ElementAttribute", }, }, }, &labeledExpr{ - pos: position{line: 377, col: 46, offset: 16722}, + pos: position{line: 384, col: 46, offset: 16940}, label: "image", expr: &ruleRefExpr{ - pos: position{line: 377, col: 52, offset: 16728}, + pos: position{line: 384, col: 52, offset: 16946}, name: "BlockImageMacro", }, }, &zeroOrMoreExpr{ - pos: position{line: 377, col: 69, offset: 16745}, + pos: position{line: 384, col: 69, offset: 16963}, expr: &ruleRefExpr{ - pos: position{line: 377, col: 69, offset: 16745}, + pos: position{line: 384, col: 69, offset: 16963}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 377, col: 73, offset: 16749}, + pos: position{line: 384, col: 73, offset: 16967}, name: "EOL", }, }, @@ -3897,44 +3932,44 @@ var g = &grammar{ }, { name: "BlockImageMacro", - pos: position{line: 382, col: 1, offset: 16910}, + pos: position{line: 389, col: 1, offset: 17128}, expr: &actionExpr{ - pos: position{line: 382, col: 20, offset: 16929}, + pos: position{line: 389, col: 20, offset: 17147}, run: (*parser).callonBlockImageMacro1, expr: &seqExpr{ - pos: position{line: 382, col: 20, offset: 16929}, + pos: position{line: 389, col: 20, offset: 17147}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 382, col: 20, offset: 16929}, + pos: position{line: 389, col: 20, offset: 17147}, val: "image::", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 382, col: 30, offset: 16939}, + pos: position{line: 389, col: 30, offset: 17157}, label: "path", expr: &ruleRefExpr{ - pos: position{line: 382, col: 36, offset: 16945}, + pos: position{line: 389, col: 36, offset: 17163}, name: "URL", }, }, &litMatcher{ - pos: position{line: 382, col: 41, offset: 16950}, + pos: position{line: 389, col: 41, offset: 17168}, val: "[", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 382, col: 45, offset: 16954}, + pos: position{line: 389, col: 45, offset: 17172}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 382, col: 57, offset: 16966}, + pos: position{line: 389, col: 57, offset: 17184}, expr: &ruleRefExpr{ - pos: position{line: 382, col: 57, offset: 16966}, + pos: position{line: 389, col: 57, offset: 17184}, name: "URL_TEXT", }, }, }, &litMatcher{ - pos: position{line: 382, col: 68, offset: 16977}, + pos: position{line: 389, col: 68, offset: 17195}, val: "]", ignoreCase: false, }, @@ -3944,15 +3979,15 @@ var g = &grammar{ }, { name: "InlineImage", - pos: position{line: 386, col: 1, offset: 17044}, + pos: position{line: 393, col: 1, offset: 17262}, expr: &actionExpr{ - pos: position{line: 386, col: 16, offset: 17059}, + pos: position{line: 393, col: 16, offset: 17277}, run: (*parser).callonInlineImage1, expr: &labeledExpr{ - pos: position{line: 386, col: 16, offset: 17059}, + pos: position{line: 393, col: 16, offset: 17277}, label: "image", expr: &ruleRefExpr{ - pos: position{line: 386, col: 22, offset: 17065}, + pos: position{line: 393, col: 22, offset: 17283}, name: "InlineImageMacro", }, }, @@ -3960,52 +3995,52 @@ var g = &grammar{ }, { name: "InlineImageMacro", - pos: position{line: 391, col: 1, offset: 17212}, + pos: position{line: 398, col: 1, offset: 17430}, expr: &actionExpr{ - pos: position{line: 391, col: 21, offset: 17232}, + pos: position{line: 398, col: 21, offset: 17450}, run: (*parser).callonInlineImageMacro1, expr: &seqExpr{ - pos: position{line: 391, col: 21, offset: 17232}, + pos: position{line: 398, col: 21, offset: 17450}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 391, col: 21, offset: 17232}, + pos: position{line: 398, col: 21, offset: 17450}, val: "image:", ignoreCase: false, }, ¬Expr{ - pos: position{line: 391, col: 30, offset: 17241}, + pos: position{line: 398, col: 30, offset: 17459}, expr: &litMatcher{ - pos: position{line: 391, col: 31, offset: 17242}, + pos: position{line: 398, col: 31, offset: 17460}, val: ":", ignoreCase: false, }, }, &labeledExpr{ - pos: position{line: 391, col: 35, offset: 17246}, + pos: position{line: 398, col: 35, offset: 17464}, label: "path", expr: &ruleRefExpr{ - pos: position{line: 391, col: 41, offset: 17252}, + pos: position{line: 398, col: 41, offset: 17470}, name: "URL", }, }, &litMatcher{ - pos: position{line: 391, col: 46, offset: 17257}, + pos: position{line: 398, col: 46, offset: 17475}, val: "[", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 391, col: 50, offset: 17261}, + pos: position{line: 398, col: 50, offset: 17479}, label: "attributes", expr: &zeroOrOneExpr{ - pos: position{line: 391, col: 62, offset: 17273}, + pos: position{line: 398, col: 62, offset: 17491}, expr: &ruleRefExpr{ - pos: position{line: 391, col: 62, offset: 17273}, + pos: position{line: 398, col: 62, offset: 17491}, name: "URL_TEXT", }, }, }, &litMatcher{ - pos: position{line: 391, col: 73, offset: 17284}, + pos: position{line: 398, col: 73, offset: 17502}, val: "]", ignoreCase: false, }, @@ -4015,16 +4050,16 @@ var g = &grammar{ }, { name: "DelimitedBlock", - pos: position{line: 398, col: 1, offset: 17614}, + pos: position{line: 405, col: 1, offset: 17832}, expr: &choiceExpr{ - pos: position{line: 398, col: 19, offset: 17632}, + pos: position{line: 405, col: 19, offset: 17850}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 398, col: 19, offset: 17632}, + pos: position{line: 405, col: 19, offset: 17850}, name: "FencedBlock", }, &ruleRefExpr{ - pos: position{line: 398, col: 33, offset: 17646}, + pos: position{line: 405, col: 33, offset: 17864}, name: "ListingBlock", }, }, @@ -4032,16 +4067,16 @@ var g = &grammar{ }, { name: "BlockDelimiter", - pos: position{line: 400, col: 1, offset: 17661}, + pos: position{line: 407, col: 1, offset: 17879}, expr: &choiceExpr{ - pos: position{line: 400, col: 19, offset: 17679}, + pos: position{line: 407, col: 19, offset: 17897}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 400, col: 19, offset: 17679}, + pos: position{line: 407, col: 19, offset: 17897}, name: "FencedBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 400, col: 42, offset: 17702}, + pos: position{line: 407, col: 42, offset: 17920}, name: "ListingBlockDelimiter", }, }, @@ -4049,58 +4084,58 @@ var g = &grammar{ }, { name: "FencedBlockDelimiter", - pos: position{line: 402, col: 1, offset: 17725}, + pos: position{line: 409, col: 1, offset: 17943}, expr: &litMatcher{ - pos: position{line: 402, col: 25, offset: 17749}, + pos: position{line: 409, col: 25, offset: 17967}, val: "```", ignoreCase: false, }, }, { name: "FencedBlock", - pos: position{line: 404, col: 1, offset: 17756}, + pos: position{line: 411, col: 1, offset: 17974}, expr: &actionExpr{ - pos: position{line: 404, col: 16, offset: 17771}, + pos: position{line: 411, col: 16, offset: 17989}, run: (*parser).callonFencedBlock1, expr: &seqExpr{ - pos: position{line: 404, col: 16, offset: 17771}, + pos: position{line: 411, col: 16, offset: 17989}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 404, col: 16, offset: 17771}, + pos: position{line: 411, col: 16, offset: 17989}, name: "FencedBlockDelimiter", }, &zeroOrMoreExpr{ - pos: position{line: 404, col: 37, offset: 17792}, + pos: position{line: 411, col: 37, offset: 18010}, expr: &ruleRefExpr{ - pos: position{line: 404, col: 37, offset: 17792}, + pos: position{line: 411, col: 37, offset: 18010}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 404, col: 41, offset: 17796}, + pos: position{line: 411, col: 41, offset: 18014}, name: "NEWLINE", }, &labeledExpr{ - pos: position{line: 404, col: 49, offset: 17804}, + pos: position{line: 411, col: 49, offset: 18022}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 404, col: 58, offset: 17813}, + pos: position{line: 411, col: 58, offset: 18031}, name: "FencedBlockContent", }, }, &ruleRefExpr{ - pos: position{line: 404, col: 78, offset: 17833}, + pos: position{line: 411, col: 78, offset: 18051}, name: "FencedBlockDelimiter", }, &zeroOrMoreExpr{ - pos: position{line: 404, col: 99, offset: 17854}, + pos: position{line: 411, col: 99, offset: 18072}, expr: &ruleRefExpr{ - pos: position{line: 404, col: 99, offset: 17854}, + pos: position{line: 411, col: 99, offset: 18072}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 404, col: 103, offset: 17858}, + pos: position{line: 411, col: 103, offset: 18076}, name: "EOL", }, }, @@ -4109,24 +4144,24 @@ var g = &grammar{ }, { name: "FencedBlockContent", - pos: position{line: 408, col: 1, offset: 17946}, + pos: position{line: 415, col: 1, offset: 18164}, expr: &labeledExpr{ - pos: position{line: 408, col: 23, offset: 17968}, + pos: position{line: 415, col: 23, offset: 18186}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 408, col: 31, offset: 17976}, + pos: position{line: 415, col: 31, offset: 18194}, expr: &seqExpr{ - pos: position{line: 408, col: 32, offset: 17977}, + pos: position{line: 415, col: 32, offset: 18195}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 408, col: 32, offset: 17977}, + pos: position{line: 415, col: 32, offset: 18195}, expr: &ruleRefExpr{ - pos: position{line: 408, col: 33, offset: 17978}, + pos: position{line: 415, col: 33, offset: 18196}, name: "FencedBlockDelimiter", }, }, &anyMatcher{ - line: 408, col: 54, offset: 17999, + line: 415, col: 54, offset: 18217, }, }, }, @@ -4135,58 +4170,58 @@ var g = &grammar{ }, { name: "ListingBlockDelimiter", - pos: position{line: 410, col: 1, offset: 18005}, + pos: position{line: 417, col: 1, offset: 18223}, expr: &litMatcher{ - pos: position{line: 410, col: 26, offset: 18030}, + pos: position{line: 417, col: 26, offset: 18248}, val: "----", ignoreCase: false, }, }, { name: "ListingBlock", - pos: position{line: 412, col: 1, offset: 18038}, + pos: position{line: 419, col: 1, offset: 18256}, expr: &actionExpr{ - pos: position{line: 412, col: 17, offset: 18054}, + pos: position{line: 419, col: 17, offset: 18272}, run: (*parser).callonListingBlock1, expr: &seqExpr{ - pos: position{line: 412, col: 17, offset: 18054}, + pos: position{line: 419, col: 17, offset: 18272}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 412, col: 17, offset: 18054}, + pos: position{line: 419, col: 17, offset: 18272}, name: "ListingBlockDelimiter", }, &zeroOrMoreExpr{ - pos: position{line: 412, col: 39, offset: 18076}, + pos: position{line: 419, col: 39, offset: 18294}, expr: &ruleRefExpr{ - pos: position{line: 412, col: 39, offset: 18076}, + pos: position{line: 419, col: 39, offset: 18294}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 412, col: 43, offset: 18080}, + pos: position{line: 419, col: 43, offset: 18298}, name: "NEWLINE", }, &labeledExpr{ - pos: position{line: 412, col: 51, offset: 18088}, + pos: position{line: 419, col: 51, offset: 18306}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 412, col: 60, offset: 18097}, + pos: position{line: 419, col: 60, offset: 18315}, name: "ListingBlockContent", }, }, &ruleRefExpr{ - pos: position{line: 412, col: 81, offset: 18118}, + pos: position{line: 419, col: 81, offset: 18336}, name: "ListingBlockDelimiter", }, &zeroOrMoreExpr{ - pos: position{line: 412, col: 103, offset: 18140}, + pos: position{line: 419, col: 103, offset: 18358}, expr: &ruleRefExpr{ - pos: position{line: 412, col: 103, offset: 18140}, + pos: position{line: 419, col: 103, offset: 18358}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 412, col: 107, offset: 18144}, + pos: position{line: 419, col: 107, offset: 18362}, name: "EOL", }, }, @@ -4195,24 +4230,24 @@ var g = &grammar{ }, { name: "ListingBlockContent", - pos: position{line: 416, col: 1, offset: 18233}, + pos: position{line: 423, col: 1, offset: 18451}, expr: &labeledExpr{ - pos: position{line: 416, col: 24, offset: 18256}, + pos: position{line: 423, col: 24, offset: 18474}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 416, col: 32, offset: 18264}, + pos: position{line: 423, col: 32, offset: 18482}, expr: &seqExpr{ - pos: position{line: 416, col: 33, offset: 18265}, + pos: position{line: 423, col: 33, offset: 18483}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 416, col: 33, offset: 18265}, + pos: position{line: 423, col: 33, offset: 18483}, expr: &ruleRefExpr{ - pos: position{line: 416, col: 34, offset: 18266}, + pos: position{line: 423, col: 34, offset: 18484}, name: "ListingBlockDelimiter", }, }, &anyMatcher{ - line: 416, col: 56, offset: 18288, + line: 423, col: 56, offset: 18506, }, }, }, @@ -4221,20 +4256,20 @@ var g = &grammar{ }, { name: "LiteralBlock", - pos: position{line: 421, col: 1, offset: 18561}, + pos: position{line: 428, col: 1, offset: 18779}, expr: &choiceExpr{ - pos: position{line: 421, col: 17, offset: 18577}, + pos: position{line: 428, col: 17, offset: 18795}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 421, col: 17, offset: 18577}, + pos: position{line: 428, col: 17, offset: 18795}, name: "ParagraphWithSpaces", }, &ruleRefExpr{ - pos: position{line: 421, col: 39, offset: 18599}, + pos: position{line: 428, col: 39, offset: 18817}, name: "ParagraphWithLiteralBlockDelimiter", }, &ruleRefExpr{ - pos: position{line: 421, col: 76, offset: 18636}, + pos: position{line: 428, col: 76, offset: 18854}, name: "ParagraphWithLiteralAttribute", }, }, @@ -4242,41 +4277,41 @@ var g = &grammar{ }, { name: "ParagraphWithSpaces", - pos: position{line: 424, col: 1, offset: 18731}, + pos: position{line: 431, col: 1, offset: 18949}, expr: &actionExpr{ - pos: position{line: 424, col: 24, offset: 18754}, + pos: position{line: 431, col: 24, offset: 18972}, run: (*parser).callonParagraphWithSpaces1, expr: &seqExpr{ - pos: position{line: 424, col: 24, offset: 18754}, + pos: position{line: 431, col: 24, offset: 18972}, exprs: []interface{}{ &labeledExpr{ - pos: position{line: 424, col: 24, offset: 18754}, + pos: position{line: 431, col: 24, offset: 18972}, label: "spaces", expr: &oneOrMoreExpr{ - pos: position{line: 424, col: 32, offset: 18762}, + pos: position{line: 431, col: 32, offset: 18980}, expr: &ruleRefExpr{ - pos: position{line: 424, col: 32, offset: 18762}, + pos: position{line: 431, col: 32, offset: 18980}, name: "WS", }, }, }, ¬Expr{ - pos: position{line: 424, col: 37, offset: 18767}, + pos: position{line: 431, col: 37, offset: 18985}, expr: &ruleRefExpr{ - pos: position{line: 424, col: 38, offset: 18768}, + pos: position{line: 431, col: 38, offset: 18986}, name: "NEWLINE", }, }, &labeledExpr{ - pos: position{line: 424, col: 46, offset: 18776}, + pos: position{line: 431, col: 46, offset: 18994}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 424, col: 55, offset: 18785}, + pos: position{line: 431, col: 55, offset: 19003}, name: "LiteralBlockContent", }, }, &ruleRefExpr{ - pos: position{line: 424, col: 76, offset: 18806}, + pos: position{line: 431, col: 76, offset: 19024}, name: "EndOfLiteralBlock", }, }, @@ -4285,36 +4320,36 @@ var g = &grammar{ }, { name: "LiteralBlockContent", - pos: position{line: 429, col: 1, offset: 18987}, + pos: position{line: 436, col: 1, offset: 19205}, expr: &actionExpr{ - pos: position{line: 429, col: 24, offset: 19010}, + pos: position{line: 436, col: 24, offset: 19228}, run: (*parser).callonLiteralBlockContent1, expr: &labeledExpr{ - pos: position{line: 429, col: 24, offset: 19010}, + pos: position{line: 436, col: 24, offset: 19228}, label: "content", expr: &oneOrMoreExpr{ - pos: position{line: 429, col: 32, offset: 19018}, + pos: position{line: 436, col: 32, offset: 19236}, expr: &seqExpr{ - pos: position{line: 429, col: 33, offset: 19019}, + pos: position{line: 436, col: 33, offset: 19237}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 429, col: 33, offset: 19019}, + pos: position{line: 436, col: 33, offset: 19237}, expr: &seqExpr{ - pos: position{line: 429, col: 35, offset: 19021}, + pos: position{line: 436, col: 35, offset: 19239}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 429, col: 35, offset: 19021}, + pos: position{line: 436, col: 35, offset: 19239}, name: "NEWLINE", }, &ruleRefExpr{ - pos: position{line: 429, col: 43, offset: 19029}, + pos: position{line: 436, col: 43, offset: 19247}, name: "BlankLine", }, }, }, }, &anyMatcher{ - line: 429, col: 54, offset: 19040, + line: 436, col: 54, offset: 19258, }, }, }, @@ -4324,29 +4359,29 @@ var g = &grammar{ }, { name: "EndOfLiteralBlock", - pos: position{line: 434, col: 1, offset: 19125}, + pos: position{line: 441, col: 1, offset: 19343}, expr: &choiceExpr{ - pos: position{line: 434, col: 22, offset: 19146}, + pos: position{line: 441, col: 22, offset: 19364}, alternatives: []interface{}{ &seqExpr{ - pos: position{line: 434, col: 22, offset: 19146}, + pos: position{line: 441, col: 22, offset: 19364}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 434, col: 22, offset: 19146}, + pos: position{line: 441, col: 22, offset: 19364}, name: "NEWLINE", }, &ruleRefExpr{ - pos: position{line: 434, col: 30, offset: 19154}, + pos: position{line: 441, col: 30, offset: 19372}, name: "BlankLine", }, }, }, &ruleRefExpr{ - pos: position{line: 434, col: 42, offset: 19166}, + pos: position{line: 441, col: 42, offset: 19384}, name: "NEWLINE", }, &ruleRefExpr{ - pos: position{line: 434, col: 52, offset: 19176}, + pos: position{line: 441, col: 52, offset: 19394}, name: "EOF", }, }, @@ -4354,63 +4389,63 @@ var g = &grammar{ }, { name: "ParagraphWithLiteralBlockDelimiter", - pos: position{line: 437, col: 1, offset: 19236}, + pos: position{line: 444, col: 1, offset: 19454}, expr: &actionExpr{ - pos: position{line: 437, col: 39, offset: 19274}, + pos: position{line: 444, col: 39, offset: 19492}, run: (*parser).callonParagraphWithLiteralBlockDelimiter1, expr: &seqExpr{ - pos: position{line: 437, col: 39, offset: 19274}, + pos: position{line: 444, col: 39, offset: 19492}, exprs: []interface{}{ &ruleRefExpr{ - pos: position{line: 437, col: 39, offset: 19274}, + pos: position{line: 444, col: 39, offset: 19492}, name: "LiteralBlockDelimiter", }, &zeroOrMoreExpr{ - pos: position{line: 437, col: 61, offset: 19296}, + pos: position{line: 444, col: 61, offset: 19514}, expr: &ruleRefExpr{ - pos: position{line: 437, col: 61, offset: 19296}, + pos: position{line: 444, col: 61, offset: 19514}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 437, col: 65, offset: 19300}, + pos: position{line: 444, col: 65, offset: 19518}, name: "NEWLINE", }, &labeledExpr{ - pos: position{line: 437, col: 73, offset: 19308}, + pos: position{line: 444, col: 73, offset: 19526}, label: "content", expr: &zeroOrMoreExpr{ - pos: position{line: 437, col: 81, offset: 19316}, + pos: position{line: 444, col: 81, offset: 19534}, expr: &seqExpr{ - pos: position{line: 437, col: 82, offset: 19317}, + pos: position{line: 444, col: 82, offset: 19535}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 437, col: 82, offset: 19317}, + pos: position{line: 444, col: 82, offset: 19535}, expr: &ruleRefExpr{ - pos: position{line: 437, col: 83, offset: 19318}, + pos: position{line: 444, col: 83, offset: 19536}, name: "LiteralBlockDelimiter", }, }, &anyMatcher{ - line: 437, col: 105, offset: 19340, + line: 444, col: 105, offset: 19558, }, }, }, }, }, &ruleRefExpr{ - pos: position{line: 437, col: 109, offset: 19344}, + pos: position{line: 444, col: 109, offset: 19562}, name: "LiteralBlockDelimiter", }, &zeroOrMoreExpr{ - pos: position{line: 437, col: 131, offset: 19366}, + pos: position{line: 444, col: 131, offset: 19584}, expr: &ruleRefExpr{ - pos: position{line: 437, col: 131, offset: 19366}, + pos: position{line: 444, col: 131, offset: 19584}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 437, col: 135, offset: 19370}, + pos: position{line: 444, col: 135, offset: 19588}, name: "EOL", }, }, @@ -4419,48 +4454,48 @@ var g = &grammar{ }, { name: "LiteralBlockDelimiter", - pos: position{line: 441, col: 1, offset: 19454}, + pos: position{line: 448, col: 1, offset: 19672}, expr: &litMatcher{ - pos: position{line: 441, col: 26, offset: 19479}, + pos: position{line: 448, col: 26, offset: 19697}, val: "....", ignoreCase: false, }, }, { name: "ParagraphWithLiteralAttribute", - pos: position{line: 444, col: 1, offset: 19541}, + pos: position{line: 451, col: 1, offset: 19759}, expr: &actionExpr{ - pos: position{line: 444, col: 34, offset: 19574}, + pos: position{line: 451, col: 34, offset: 19792}, run: (*parser).callonParagraphWithLiteralAttribute1, expr: &seqExpr{ - pos: position{line: 444, col: 34, offset: 19574}, + pos: position{line: 451, col: 34, offset: 19792}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 444, col: 34, offset: 19574}, + pos: position{line: 451, col: 34, offset: 19792}, val: "[literal]", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 444, col: 46, offset: 19586}, + pos: position{line: 451, col: 46, offset: 19804}, expr: &ruleRefExpr{ - pos: position{line: 444, col: 46, offset: 19586}, + pos: position{line: 451, col: 46, offset: 19804}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 444, col: 50, offset: 19590}, + pos: position{line: 451, col: 50, offset: 19808}, name: "NEWLINE", }, &labeledExpr{ - pos: position{line: 444, col: 58, offset: 19598}, + pos: position{line: 451, col: 58, offset: 19816}, label: "content", expr: &ruleRefExpr{ - pos: position{line: 444, col: 67, offset: 19607}, + pos: position{line: 451, col: 67, offset: 19825}, name: "LiteralBlockContent", }, }, &ruleRefExpr{ - pos: position{line: 444, col: 88, offset: 19628}, + pos: position{line: 451, col: 88, offset: 19846}, name: "EndOfLiteralBlock", }, }, @@ -4469,96 +4504,72 @@ var g = &grammar{ }, { name: "ElementAttribute", - pos: position{line: 451, col: 1, offset: 19840}, - expr: &labeledExpr{ - pos: position{line: 451, col: 21, offset: 19860}, - label: "meta", - expr: &choiceExpr{ - pos: position{line: 451, col: 27, offset: 19866}, - alternatives: []interface{}{ - &ruleRefExpr{ - pos: position{line: 451, col: 27, offset: 19866}, - name: "ElementLink", - }, - &ruleRefExpr{ - pos: position{line: 451, col: 41, offset: 19880}, - name: "ElementID", - }, - &ruleRefExpr{ - pos: position{line: 451, col: 53, offset: 19892}, - name: "ElementTitle", - }, + pos: position{line: 458, col: 1, offset: 20058}, + expr: &choiceExpr{ + pos: position{line: 458, col: 21, offset: 20078}, + alternatives: []interface{}{ + &ruleRefExpr{ + pos: position{line: 458, col: 21, offset: 20078}, + name: "ElementLink", + }, + &ruleRefExpr{ + pos: position{line: 458, col: 35, offset: 20092}, + name: "ElementID", + }, + &ruleRefExpr{ + pos: position{line: 458, col: 47, offset: 20104}, + name: "ElementTitle", + }, + &ruleRefExpr{ + pos: position{line: 458, col: 62, offset: 20119}, + name: "InvalidElementAttribute", }, }, }, }, { name: "ElementLink", - pos: position{line: 454, col: 1, offset: 19963}, + pos: position{line: 461, col: 1, offset: 20199}, expr: &actionExpr{ - pos: position{line: 454, col: 16, offset: 19978}, + pos: position{line: 461, col: 16, offset: 20214}, run: (*parser).callonElementLink1, expr: &seqExpr{ - pos: position{line: 454, col: 16, offset: 19978}, + pos: position{line: 461, col: 16, offset: 20214}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 454, col: 16, offset: 19978}, - val: "[", - ignoreCase: false, - }, - &zeroOrMoreExpr{ - pos: position{line: 454, col: 20, offset: 19982}, - expr: &ruleRefExpr{ - pos: position{line: 454, col: 20, offset: 19982}, - name: "WS", - }, - }, - &litMatcher{ - pos: position{line: 454, col: 24, offset: 19986}, - val: "link", - ignoreCase: false, - }, - &zeroOrMoreExpr{ - pos: position{line: 454, col: 31, offset: 19993}, - expr: &ruleRefExpr{ - pos: position{line: 454, col: 31, offset: 19993}, - name: "WS", - }, - }, - &litMatcher{ - pos: position{line: 454, col: 35, offset: 19997}, - val: "=", + pos: position{line: 461, col: 16, offset: 20214}, + val: "[link=", ignoreCase: false, }, &zeroOrMoreExpr{ - pos: position{line: 454, col: 39, offset: 20001}, + pos: position{line: 461, col: 25, offset: 20223}, expr: &ruleRefExpr{ - pos: position{line: 454, col: 39, offset: 20001}, + pos: position{line: 461, col: 25, offset: 20223}, name: "WS", }, }, &labeledExpr{ - pos: position{line: 454, col: 43, offset: 20005}, + pos: position{line: 461, col: 29, offset: 20227}, label: "path", expr: &ruleRefExpr{ - pos: position{line: 454, col: 48, offset: 20010}, + pos: position{line: 461, col: 34, offset: 20232}, name: "URL", }, }, &zeroOrMoreExpr{ - pos: position{line: 454, col: 52, offset: 20014}, + pos: position{line: 461, col: 38, offset: 20236}, expr: &ruleRefExpr{ - pos: position{line: 454, col: 52, offset: 20014}, + pos: position{line: 461, col: 38, offset: 20236}, name: "WS", }, }, &litMatcher{ - pos: position{line: 454, col: 56, offset: 20018}, + pos: position{line: 461, col: 42, offset: 20240}, val: "]", ignoreCase: false, }, &ruleRefExpr{ - pos: position{line: 454, col: 60, offset: 20022}, + pos: position{line: 461, col: 46, offset: 20244}, name: "EOL", }, }, @@ -4567,52 +4578,85 @@ var g = &grammar{ }, { name: "ElementID", - pos: position{line: 459, col: 1, offset: 20132}, + pos: position{line: 465, col: 1, offset: 20300}, + expr: &choiceExpr{ + pos: position{line: 465, col: 14, offset: 20313}, + alternatives: []interface{}{ + &ruleRefExpr{ + pos: position{line: 465, col: 14, offset: 20313}, + name: "ElementIDNormal", + }, + &ruleRefExpr{ + pos: position{line: 465, col: 32, offset: 20331}, + name: "ElementIDShortHand", + }, + }, + }, + }, + { + name: "ElementIDNormal", + pos: position{line: 468, col: 1, offset: 20405}, expr: &actionExpr{ - pos: position{line: 459, col: 14, offset: 20145}, - run: (*parser).callonElementID1, + pos: position{line: 468, col: 20, offset: 20424}, + run: (*parser).callonElementIDNormal1, expr: &seqExpr{ - pos: position{line: 459, col: 14, offset: 20145}, + pos: position{line: 468, col: 20, offset: 20424}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 459, col: 14, offset: 20145}, - val: "[", + pos: position{line: 468, col: 20, offset: 20424}, + val: "[[", ignoreCase: false, }, - &zeroOrMoreExpr{ - pos: position{line: 459, col: 18, offset: 20149}, + &labeledExpr{ + pos: position{line: 468, col: 25, offset: 20429}, + label: "id", expr: &ruleRefExpr{ - pos: position{line: 459, col: 18, offset: 20149}, - name: "WS", + pos: position{line: 468, col: 29, offset: 20433}, + name: "ID", }, }, &litMatcher{ - pos: position{line: 459, col: 22, offset: 20153}, - val: "#", + pos: position{line: 468, col: 33, offset: 20437}, + val: "]]", + ignoreCase: false, + }, + &ruleRefExpr{ + pos: position{line: 468, col: 38, offset: 20442}, + name: "EOL", + }, + }, + }, + }, + }, + { + name: "ElementIDShortHand", + pos: position{line: 471, col: 1, offset: 20493}, + expr: &actionExpr{ + pos: position{line: 471, col: 23, offset: 20515}, + run: (*parser).callonElementIDShortHand1, + expr: &seqExpr{ + pos: position{line: 471, col: 23, offset: 20515}, + exprs: []interface{}{ + &litMatcher{ + pos: position{line: 471, col: 23, offset: 20515}, + val: "[#", ignoreCase: false, }, &labeledExpr{ - pos: position{line: 459, col: 26, offset: 20157}, + pos: position{line: 471, col: 28, offset: 20520}, label: "id", expr: &ruleRefExpr{ - pos: position{line: 459, col: 30, offset: 20161}, + pos: position{line: 471, col: 32, offset: 20524}, name: "ID", }, }, - &zeroOrMoreExpr{ - pos: position{line: 459, col: 34, offset: 20165}, - expr: &ruleRefExpr{ - pos: position{line: 459, col: 34, offset: 20165}, - name: "WS", - }, - }, &litMatcher{ - pos: position{line: 459, col: 38, offset: 20169}, + pos: position{line: 471, col: 36, offset: 20528}, val: "]", ignoreCase: false, }, &ruleRefExpr{ - pos: position{line: 459, col: 42, offset: 20173}, + pos: position{line: 471, col: 40, offset: 20532}, name: "EOL", }, }, @@ -4621,88 +4665,141 @@ var g = &grammar{ }, { name: "ElementTitle", - pos: position{line: 465, col: 1, offset: 20367}, + pos: position{line: 477, col: 1, offset: 20726}, expr: &actionExpr{ - pos: position{line: 465, col: 17, offset: 20383}, + pos: position{line: 477, col: 17, offset: 20742}, run: (*parser).callonElementTitle1, expr: &seqExpr{ - pos: position{line: 465, col: 17, offset: 20383}, + pos: position{line: 477, col: 17, offset: 20742}, exprs: []interface{}{ &litMatcher{ - pos: position{line: 465, col: 17, offset: 20383}, + pos: position{line: 477, col: 17, offset: 20742}, val: ".", ignoreCase: false, }, ¬Expr{ - pos: position{line: 465, col: 21, offset: 20387}, + pos: position{line: 477, col: 21, offset: 20746}, expr: &litMatcher{ - pos: position{line: 465, col: 22, offset: 20388}, + pos: position{line: 477, col: 22, offset: 20747}, val: ".", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 465, col: 26, offset: 20392}, + pos: position{line: 477, col: 26, offset: 20751}, expr: &ruleRefExpr{ - pos: position{line: 465, col: 27, offset: 20393}, + pos: position{line: 477, col: 27, offset: 20752}, name: "WS", }, }, &labeledExpr{ - pos: position{line: 465, col: 30, offset: 20396}, + pos: position{line: 477, col: 30, offset: 20755}, label: "title", expr: &oneOrMoreExpr{ - pos: position{line: 465, col: 36, offset: 20402}, + pos: position{line: 477, col: 36, offset: 20761}, expr: &seqExpr{ - pos: position{line: 465, col: 37, offset: 20403}, + pos: position{line: 477, col: 37, offset: 20762}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 465, col: 37, offset: 20403}, + pos: position{line: 477, col: 37, offset: 20762}, expr: &ruleRefExpr{ - pos: position{line: 465, col: 38, offset: 20404}, + pos: position{line: 477, col: 38, offset: 20763}, name: "NEWLINE", }, }, &anyMatcher{ - line: 465, col: 46, offset: 20412, + line: 477, col: 46, offset: 20771, }, }, }, }, }, &ruleRefExpr{ - pos: position{line: 465, col: 50, offset: 20416}, + pos: position{line: 477, col: 50, offset: 20775}, name: "EOL", }, }, }, }, }, + { + name: "InvalidElementAttribute", + pos: position{line: 481, col: 1, offset: 20840}, + expr: &actionExpr{ + pos: position{line: 481, col: 28, offset: 20867}, + run: (*parser).callonInvalidElementAttribute1, + expr: &seqExpr{ + pos: position{line: 481, col: 28, offset: 20867}, + exprs: []interface{}{ + &litMatcher{ + pos: position{line: 481, col: 28, offset: 20867}, + val: "[", + ignoreCase: false, + }, + &oneOrMoreExpr{ + pos: position{line: 481, col: 32, offset: 20871}, + expr: &ruleRefExpr{ + pos: position{line: 481, col: 32, offset: 20871}, + name: "WS", + }, + }, + &labeledExpr{ + pos: position{line: 481, col: 36, offset: 20875}, + label: "content", + expr: &zeroOrMoreExpr{ + pos: position{line: 481, col: 44, offset: 20883}, + expr: &seqExpr{ + pos: position{line: 481, col: 45, offset: 20884}, + exprs: []interface{}{ + ¬Expr{ + pos: position{line: 481, col: 45, offset: 20884}, + expr: &litMatcher{ + pos: position{line: 481, col: 46, offset: 20885}, + val: "]", + ignoreCase: false, + }, + }, + &anyMatcher{ + line: 481, col: 50, offset: 20889, + }, + }, + }, + }, + }, + &litMatcher{ + pos: position{line: 481, col: 54, offset: 20893}, + val: "]", + ignoreCase: false, + }, + }, + }, + }, + }, { name: "BlankLine", - pos: position{line: 472, col: 1, offset: 20586}, + pos: position{line: 488, col: 1, offset: 21059}, expr: &actionExpr{ - pos: position{line: 472, col: 14, offset: 20599}, + pos: position{line: 488, col: 14, offset: 21072}, run: (*parser).callonBlankLine1, expr: &seqExpr{ - pos: position{line: 472, col: 14, offset: 20599}, + pos: position{line: 488, col: 14, offset: 21072}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 472, col: 14, offset: 20599}, + pos: position{line: 488, col: 14, offset: 21072}, expr: &ruleRefExpr{ - pos: position{line: 472, col: 15, offset: 20600}, + pos: position{line: 488, col: 15, offset: 21073}, name: "EOF", }, }, &zeroOrMoreExpr{ - pos: position{line: 472, col: 19, offset: 20604}, + pos: position{line: 488, col: 19, offset: 21077}, expr: &ruleRefExpr{ - pos: position{line: 472, col: 19, offset: 20604}, + pos: position{line: 488, col: 19, offset: 21077}, name: "WS", }, }, &ruleRefExpr{ - pos: position{line: 472, col: 23, offset: 20608}, + pos: position{line: 488, col: 23, offset: 21081}, name: "EOL", }, }, @@ -4711,31 +4808,31 @@ var g = &grammar{ }, { name: "Characters", - pos: position{line: 479, col: 1, offset: 20755}, + pos: position{line: 495, col: 1, offset: 21228}, expr: &actionExpr{ - pos: position{line: 479, col: 15, offset: 20769}, + pos: position{line: 495, col: 15, offset: 21242}, run: (*parser).callonCharacters1, expr: &oneOrMoreExpr{ - pos: position{line: 479, col: 15, offset: 20769}, + pos: position{line: 495, col: 15, offset: 21242}, expr: &seqExpr{ - pos: position{line: 479, col: 16, offset: 20770}, + pos: position{line: 495, col: 16, offset: 21243}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 479, col: 16, offset: 20770}, + pos: position{line: 495, col: 16, offset: 21243}, expr: &ruleRefExpr{ - pos: position{line: 479, col: 17, offset: 20771}, + pos: position{line: 495, col: 17, offset: 21244}, name: "NEWLINE", }, }, ¬Expr{ - pos: position{line: 479, col: 25, offset: 20779}, + pos: position{line: 495, col: 25, offset: 21252}, expr: &ruleRefExpr{ - pos: position{line: 479, col: 26, offset: 20780}, + pos: position{line: 495, col: 26, offset: 21253}, name: "WS", }, }, &anyMatcher{ - line: 479, col: 29, offset: 20783, + line: 495, col: 29, offset: 21256, }, }, }, @@ -4744,47 +4841,47 @@ var g = &grammar{ }, { name: "URL", - pos: position{line: 484, col: 1, offset: 20824}, + pos: position{line: 500, col: 1, offset: 21297}, expr: &actionExpr{ - pos: position{line: 484, col: 8, offset: 20831}, + pos: position{line: 500, col: 8, offset: 21304}, run: (*parser).callonURL1, expr: &oneOrMoreExpr{ - pos: position{line: 484, col: 8, offset: 20831}, + pos: position{line: 500, col: 8, offset: 21304}, expr: &seqExpr{ - pos: position{line: 484, col: 9, offset: 20832}, + pos: position{line: 500, col: 9, offset: 21305}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 484, col: 9, offset: 20832}, + pos: position{line: 500, col: 9, offset: 21305}, expr: &ruleRefExpr{ - pos: position{line: 484, col: 10, offset: 20833}, + pos: position{line: 500, col: 10, offset: 21306}, name: "NEWLINE", }, }, ¬Expr{ - pos: position{line: 484, col: 18, offset: 20841}, + pos: position{line: 500, col: 18, offset: 21314}, expr: &ruleRefExpr{ - pos: position{line: 484, col: 19, offset: 20842}, + pos: position{line: 500, col: 19, offset: 21315}, name: "WS", }, }, ¬Expr{ - pos: position{line: 484, col: 22, offset: 20845}, + pos: position{line: 500, col: 22, offset: 21318}, expr: &litMatcher{ - pos: position{line: 484, col: 23, offset: 20846}, + pos: position{line: 500, col: 23, offset: 21319}, val: "[", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 484, col: 27, offset: 20850}, + pos: position{line: 500, col: 27, offset: 21323}, expr: &litMatcher{ - pos: position{line: 484, col: 28, offset: 20851}, + pos: position{line: 500, col: 28, offset: 21324}, val: "]", ignoreCase: false, }, }, &anyMatcher{ - line: 484, col: 32, offset: 20855, + line: 500, col: 32, offset: 21328, }, }, }, @@ -4793,47 +4890,63 @@ var g = &grammar{ }, { name: "ID", - pos: position{line: 488, col: 1, offset: 20895}, + pos: position{line: 504, col: 1, offset: 21368}, expr: &actionExpr{ - pos: position{line: 488, col: 7, offset: 20901}, + pos: position{line: 504, col: 7, offset: 21374}, run: (*parser).callonID1, expr: &oneOrMoreExpr{ - pos: position{line: 488, col: 7, offset: 20901}, + pos: position{line: 504, col: 7, offset: 21374}, expr: &seqExpr{ - pos: position{line: 488, col: 8, offset: 20902}, + pos: position{line: 504, col: 8, offset: 21375}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 488, col: 8, offset: 20902}, + pos: position{line: 504, col: 8, offset: 21375}, expr: &ruleRefExpr{ - pos: position{line: 488, col: 9, offset: 20903}, + pos: position{line: 504, col: 9, offset: 21376}, name: "NEWLINE", }, }, ¬Expr{ - pos: position{line: 488, col: 17, offset: 20911}, + pos: position{line: 504, col: 17, offset: 21384}, expr: &ruleRefExpr{ - pos: position{line: 488, col: 18, offset: 20912}, + pos: position{line: 504, col: 18, offset: 21385}, name: "WS", }, }, ¬Expr{ - pos: position{line: 488, col: 21, offset: 20915}, + pos: position{line: 504, col: 21, offset: 21388}, expr: &litMatcher{ - pos: position{line: 488, col: 22, offset: 20916}, + pos: position{line: 504, col: 22, offset: 21389}, val: "[", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 488, col: 26, offset: 20920}, + pos: position{line: 504, col: 26, offset: 21393}, expr: &litMatcher{ - pos: position{line: 488, col: 27, offset: 20921}, + pos: position{line: 504, col: 27, offset: 21394}, val: "]", ignoreCase: false, }, }, + ¬Expr{ + pos: position{line: 504, col: 31, offset: 21398}, + expr: &litMatcher{ + pos: position{line: 504, col: 32, offset: 21399}, + val: "<<", + ignoreCase: false, + }, + }, + ¬Expr{ + pos: position{line: 504, col: 37, offset: 21404}, + expr: &litMatcher{ + pos: position{line: 504, col: 38, offset: 21405}, + val: ">>", + ignoreCase: false, + }, + }, &anyMatcher{ - line: 488, col: 31, offset: 20925, + line: 504, col: 42, offset: 21409, }, }, }, @@ -4842,40 +4955,40 @@ var g = &grammar{ }, { name: "URL_TEXT", - pos: position{line: 492, col: 1, offset: 20965}, + pos: position{line: 508, col: 1, offset: 21449}, expr: &actionExpr{ - pos: position{line: 492, col: 13, offset: 20977}, + pos: position{line: 508, col: 13, offset: 21461}, run: (*parser).callonURL_TEXT1, expr: &oneOrMoreExpr{ - pos: position{line: 492, col: 13, offset: 20977}, + pos: position{line: 508, col: 13, offset: 21461}, expr: &seqExpr{ - pos: position{line: 492, col: 14, offset: 20978}, + pos: position{line: 508, col: 14, offset: 21462}, exprs: []interface{}{ ¬Expr{ - pos: position{line: 492, col: 14, offset: 20978}, + pos: position{line: 508, col: 14, offset: 21462}, expr: &ruleRefExpr{ - pos: position{line: 492, col: 15, offset: 20979}, + pos: position{line: 508, col: 15, offset: 21463}, name: "NEWLINE", }, }, ¬Expr{ - pos: position{line: 492, col: 23, offset: 20987}, + pos: position{line: 508, col: 23, offset: 21471}, expr: &litMatcher{ - pos: position{line: 492, col: 24, offset: 20988}, + pos: position{line: 508, col: 24, offset: 21472}, val: "[", ignoreCase: false, }, }, ¬Expr{ - pos: position{line: 492, col: 28, offset: 20992}, + pos: position{line: 508, col: 28, offset: 21476}, expr: &litMatcher{ - pos: position{line: 492, col: 29, offset: 20993}, + pos: position{line: 508, col: 29, offset: 21477}, val: "]", ignoreCase: false, }, }, &anyMatcher{ - line: 492, col: 33, offset: 20997, + line: 508, col: 33, offset: 21481, }, }, }, @@ -4884,32 +4997,32 @@ var g = &grammar{ }, { name: "URL_SCHEME", - pos: position{line: 496, col: 1, offset: 21037}, + pos: position{line: 512, col: 1, offset: 21521}, expr: &choiceExpr{ - pos: position{line: 496, col: 15, offset: 21051}, + pos: position{line: 512, col: 15, offset: 21535}, alternatives: []interface{}{ &litMatcher{ - pos: position{line: 496, col: 15, offset: 21051}, + pos: position{line: 512, col: 15, offset: 21535}, val: "http://", ignoreCase: false, }, &litMatcher{ - pos: position{line: 496, col: 27, offset: 21063}, + pos: position{line: 512, col: 27, offset: 21547}, val: "https://", ignoreCase: false, }, &litMatcher{ - pos: position{line: 496, col: 40, offset: 21076}, + pos: position{line: 512, col: 40, offset: 21560}, val: "ftp://", ignoreCase: false, }, &litMatcher{ - pos: position{line: 496, col: 51, offset: 21087}, + pos: position{line: 512, col: 51, offset: 21571}, val: "irc://", ignoreCase: false, }, &litMatcher{ - pos: position{line: 496, col: 62, offset: 21098}, + pos: position{line: 512, col: 62, offset: 21582}, val: "mailto:", ignoreCase: false, }, @@ -4918,9 +5031,9 @@ var g = &grammar{ }, { name: "DIGIT", - pos: position{line: 498, col: 1, offset: 21109}, + pos: position{line: 514, col: 1, offset: 21593}, expr: &charClassMatcher{ - pos: position{line: 498, col: 13, offset: 21121}, + pos: position{line: 514, col: 13, offset: 21605}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -4929,22 +5042,22 @@ var g = &grammar{ }, { name: "NEWLINE", - pos: position{line: 500, col: 1, offset: 21128}, + pos: position{line: 516, col: 1, offset: 21612}, expr: &choiceExpr{ - pos: position{line: 500, col: 13, offset: 21140}, + pos: position{line: 516, col: 13, offset: 21624}, alternatives: []interface{}{ &litMatcher{ - pos: position{line: 500, col: 13, offset: 21140}, + pos: position{line: 516, col: 13, offset: 21624}, val: "\r\n", ignoreCase: false, }, &litMatcher{ - pos: position{line: 500, col: 22, offset: 21149}, + pos: position{line: 516, col: 22, offset: 21633}, val: "\r", ignoreCase: false, }, &litMatcher{ - pos: position{line: 500, col: 29, offset: 21156}, + pos: position{line: 516, col: 29, offset: 21640}, val: "\n", ignoreCase: false, }, @@ -4953,20 +5066,20 @@ var g = &grammar{ }, { name: "WS", - pos: position{line: 502, col: 1, offset: 21162}, + pos: position{line: 518, col: 1, offset: 21646}, expr: &choiceExpr{ - pos: position{line: 502, col: 13, offset: 21174}, + pos: position{line: 518, col: 13, offset: 21658}, alternatives: []interface{}{ &litMatcher{ - pos: position{line: 502, col: 13, offset: 21174}, + pos: position{line: 518, col: 13, offset: 21658}, val: " ", ignoreCase: false, }, &actionExpr{ - pos: position{line: 502, col: 19, offset: 21180}, + pos: position{line: 518, col: 19, offset: 21664}, run: (*parser).callonWS3, expr: &litMatcher{ - pos: position{line: 502, col: 19, offset: 21180}, + pos: position{line: 518, col: 19, offset: 21664}, val: "\t", ignoreCase: false, }, @@ -4976,26 +5089,26 @@ var g = &grammar{ }, { name: "EOF", - pos: position{line: 506, col: 1, offset: 21225}, + pos: position{line: 522, col: 1, offset: 21709}, expr: ¬Expr{ - pos: position{line: 506, col: 13, offset: 21237}, + pos: position{line: 522, col: 13, offset: 21721}, expr: &anyMatcher{ - line: 506, col: 14, offset: 21238, + line: 522, col: 14, offset: 21722, }, }, }, { name: "EOL", - pos: position{line: 508, col: 1, offset: 21241}, + pos: position{line: 524, col: 1, offset: 21725}, expr: &choiceExpr{ - pos: position{line: 508, col: 13, offset: 21253}, + pos: position{line: 524, col: 13, offset: 21737}, alternatives: []interface{}{ &ruleRefExpr{ - pos: position{line: 508, col: 13, offset: 21253}, + pos: position{line: 524, col: 13, offset: 21737}, name: "NEWLINE", }, &ruleRefExpr{ - pos: position{line: 508, col: 23, offset: 21263}, + pos: position{line: 524, col: 23, offset: 21747}, name: "EOF", }, }, @@ -5612,6 +5725,16 @@ func (p *parser) callonPassthroughWithQuotedText1() (interface{}, error) { return p.cur.onPassthroughWithQuotedText1(stack["content"]) } +func (c *current) onCrossReference1(id interface{}) (interface{}, error) { + return types.NewCrossReference(id.(string)) +} + +func (p *parser) callonCrossReference1() (interface{}, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onCrossReference1(stack["id"]) +} + func (c *current) onExternalLink1(url, text interface{}) (interface{}, error) { if text != nil { return types.NewExternalLink(url.([]interface{}), text.([]interface{})) @@ -5738,14 +5861,24 @@ func (p *parser) callonElementLink1() (interface{}, error) { return p.cur.onElementLink1(stack["path"]) } -func (c *current) onElementID1(id interface{}) (interface{}, error) { +func (c *current) onElementIDNormal1(id interface{}) (interface{}, error) { return types.NewElementID(id.(string)) } -func (p *parser) callonElementID1() (interface{}, error) { +func (p *parser) callonElementIDNormal1() (interface{}, error) { stack := p.vstack[len(p.vstack)-1] _ = stack - return p.cur.onElementID1(stack["id"]) + return p.cur.onElementIDNormal1(stack["id"]) +} + +func (c *current) onElementIDShortHand1(id interface{}) (interface{}, error) { + return types.NewElementID(id.(string)) +} + +func (p *parser) callonElementIDShortHand1() (interface{}, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onElementIDShortHand1(stack["id"]) } func (c *current) onElementTitle1(title interface{}) (interface{}, error) { @@ -5758,6 +5891,16 @@ func (p *parser) callonElementTitle1() (interface{}, error) { return p.cur.onElementTitle1(stack["title"]) } +func (c *current) onInvalidElementAttribute1(content interface{}) (interface{}, error) { + return types.NewInvalidElementAttribute(c.text) +} + +func (p *parser) callonInvalidElementAttribute1() (interface{}, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onInvalidElementAttribute1(stack["content"]) +} + func (c *current) onBlankLine1() (interface{}, error) { return types.NewBlankLine() } diff --git a/parser/asciidoc_parser_test.go b/parser/asciidoc_parser_test.go index 452a1ec2..84b1b40d 100644 --- a/parser/asciidoc_parser_test.go +++ b/parser/asciidoc_parser_test.go @@ -23,3 +23,13 @@ func verify(t GinkgoTInterface, expectedDocument interface{}, content string, op t.Logf("expected document: `%s`", spew.Sdump(expectedDocument)) assert.EqualValues(t, expectedDocument, result) } + +func expectError(t GinkgoTInterface, content string, options ...parser.Option) { + log.Debugf("processing: %s", content) + reader := strings.NewReader(content) + _, err := parser.ParseReader("", reader, options...) //, Debug(true)) + if err == nil { + log.Error("Expected an error while parsing the document, but none was reported") + } + require.Error(t, err) +} diff --git a/parser/blank_line_test.go b/parser/blank_line_test.go index 561a1a0f..c3f18d72 100644 --- a/parser/blank_line_test.go +++ b/parser/blank_line_test.go @@ -11,7 +11,8 @@ var _ = Describe("Blank lines", func() { second paragraph` expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ @@ -43,7 +44,8 @@ second paragraph` second paragraph ` expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ diff --git a/parser/cross_reference_test.go b/parser/cross_reference_test.go new file mode 100644 index 00000000..c129c342 --- /dev/null +++ b/parser/cross_reference_test.go @@ -0,0 +1,28 @@ +package parser_test + +import ( + "github.com/bytesparadise/libasciidoc/parser" + "github.com/bytesparadise/libasciidoc/types" + . "github.com/onsi/ginkgo" +) + +var _ = Describe("Cross References", func() { + + Context("Reference to section", func() { + + Context("valid reference", func() { + + It("xref with custom id", func() { + actualContent := `a link to <>.` + expectedResult := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a link to "}, + &types.CrossReference{ID: "thetitle"}, + &types.StringElement{Content: "."}, + }, + } + verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("InlineContent")) + }) + }) + }) +}) diff --git a/parser/delimited_block_test.go b/parser/delimited_block_test.go index 05722a3d..14c8c368 100644 --- a/parser/delimited_block_test.go +++ b/parser/delimited_block_test.go @@ -13,7 +13,8 @@ var _ = Describe("Delimited Blocks", func() { content := "some fenced code" actualContent := "```\n" + content + "\n```" expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DelimitedBlock{ Kind: types.FencedBlock, @@ -28,7 +29,8 @@ var _ = Describe("Delimited Blocks", func() { content := "" actualContent := "```\n" + content + "```" expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DelimitedBlock{ Kind: types.FencedBlock, @@ -43,7 +45,8 @@ var _ = Describe("Delimited Blocks", func() { content := "some fenced code\nwith an empty line\n\nin the middle" actualContent := "```\n" + content + "\n```" expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DelimitedBlock{ Kind: types.FencedBlock, @@ -58,7 +61,8 @@ var _ = Describe("Delimited Blocks", func() { content := "some fenced code\nwith an empty line\n\nin the middle" actualContent := "```\n" + content + "\n```\nthen a normal paragraph." expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DelimitedBlock{ Kind: types.FencedBlock, @@ -82,7 +86,8 @@ var _ = Describe("Delimited Blocks", func() { content := "some fenced code" actualContent := "a paragraph.\n```\n" + content + "\n```\n" expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ @@ -110,7 +115,8 @@ var _ = Describe("Delimited Blocks", func() { some listing code ----` expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DelimitedBlock{ Kind: types.ListingBlock, @@ -125,7 +131,8 @@ some listing code content := "" actualContent := "----\n" + content + "----" expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DelimitedBlock{ Kind: types.ListingBlock, @@ -140,7 +147,8 @@ some listing code content := "some listing code\nwith an empty line\n\nin the middle" actualContent := "----\n" + content + "\n----" expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DelimitedBlock{ Kind: types.ListingBlock, @@ -155,7 +163,8 @@ some listing code content := "some listing code\nwith an empty line\n\nin the middle" actualContent := "----\n" + content + "\n----\nthen a normal paragraph." expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DelimitedBlock{ Kind: types.ListingBlock, @@ -182,7 +191,8 @@ some listing code some listing code ----` expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ diff --git a/parser/document_attributes_test.go b/parser/document_attributes_test.go index 90ad45e1..2af553f2 100644 --- a/parser/document_attributes_test.go +++ b/parser/document_attributes_test.go @@ -27,6 +27,7 @@ This journey begins on a bleary Monday morning.` }, }, }, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ @@ -295,7 +296,8 @@ This journey begins on a bleary Monday morning.` :0Author: Xavier :Auth0r: Xavier` expectedResult := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DocumentAttributeDeclaration{Name: "a"}, &types.DocumentAttributeDeclaration{Name: "author", Value: "Xavier"}, @@ -314,7 +316,8 @@ This journey begins on a bleary Monday morning.` :author: Xavier a paragraph` expectedResult := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DocumentAttributeDeclaration{Name: "toc"}, &types.DocumentAttributeDeclaration{Name: "date", Value: "2017-01-01"}, @@ -340,7 +343,8 @@ a paragraph` a paragraph` expectedResult := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DocumentAttributeDeclaration{Name: "toc"}, &types.DocumentAttributeDeclaration{Name: "date", Value: "2017-01-01"}, @@ -367,7 +371,8 @@ a paragraph` a paragraph` expectedResult := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DocumentAttributeDeclaration{Name: "toc"}, &types.DocumentAttributeDeclaration{Name: "date", Value: "2017-01-01"}, @@ -393,7 +398,8 @@ a paragraph` :date: 2017-01-01 :author: Xavier` expectedResult := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ @@ -420,7 +426,8 @@ a paragraph` a paragraph written by {author}.` expectedResult := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DocumentAttributeDeclaration{Name: "author", Value: "Xavier"}, &types.Paragraph{ @@ -446,7 +453,8 @@ a paragraph written by {author}.` :author2!: a paragraph written by {author}.` expectedResult := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.DocumentAttributeDeclaration{Name: "author", Value: "Xavier"}, &types.DocumentAttributeReset{Name: "author1"}, @@ -505,6 +513,7 @@ This journey begins on a bleary Monday morning.` "keywords": "documentation, team, obstacles, journey, victory", "toc": "", }, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.TableOfContentsMacro{}, &types.Paragraph{ @@ -541,6 +550,18 @@ a paragraph with *bold content*` }, }, }, + ElementReferences: map[string]interface{}{ + "_section_1": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "section 1"}, + }, + }, + ID: &types.ElementID{ + Value: "_section_1", + }, + }, + }, Elements: []types.DocElement{ &types.Section{ Level: 1, @@ -585,7 +606,8 @@ a paragraph with *bold content*` :date: 2017-01-01 :author: Xavier` expectedResult := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ @@ -620,7 +642,8 @@ a paragraph with *bold content*` actualContent := `:@date: 2017-01-01 :{author}: Xavier` expectedResult := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ diff --git a/parser/element_attributes_test.go b/parser/element_attributes_test.go new file mode 100644 index 00000000..50fe8c04 --- /dev/null +++ b/parser/element_attributes_test.go @@ -0,0 +1,149 @@ +package parser_test + +import ( + "github.com/bytesparadise/libasciidoc/parser" + "github.com/bytesparadise/libasciidoc/types" + . "github.com/onsi/ginkgo" +) + +var _ = Describe("Element Attributes", func() { + + Context("Element link", func() { + + Context("valid syntax", func() { + It("element link alone", func() { + actualContent := "[link=http://foo.bar]" + expectedDocument := &types.ElementLink{Path: "http://foo.bar"} + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("ElementAttribute")) + }) + It("spaces in link", func() { + actualContent := "[link= http://foo.bar ]" + expectedDocument := &types.ElementLink{Path: "http://foo.bar"} + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("ElementAttribute")) + }) + }) + + Context("invalid syntax", func() { + It("spaces before keywork", func() { + actualContent := "[ link=http://foo.bar]" + expectedDocument := &types.InvalidElementAttribute{Value: "[ link=http://foo.bar]"} + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("ElementAttribute")) + }) + + Context("unbalanced brackets", func() { + actualContent := "[link=http://foo.bar" + It("cannot be an attribute", func() { + expectError(GinkgoT(), actualContent, parser.Entrypoint("ElementAttribute")) + }) + + It("is an inline content", func() { + expectedDocument := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{ + Content: "[link=http://foo.bar", + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("InlineContent")) + }) + }) + }) + }) + + Context("element id", func() { + + Context("valid syntax", func() { + + It("normal syntax", func() { + actualContent := "[[img-foobar]]" + expectedDocument := &types.ElementID{Value: "img-foobar"} + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("ElementAttribute")) + }) + + It("short-hand syntax", func() { + actualContent := "[#img-foobar]" + expectedDocument := &types.ElementID{Value: "img-foobar"} + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("ElementAttribute")) + }) + }) + + Context("invalid syntax", func() { + + It("extra spaces", func() { + actualContent := "[ #img-foobar ]" + expectedDocument := &types.InvalidElementAttribute{Value: "[ #img-foobar ]"} + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("ElementAttribute")) + }) + + Context("unbalanced brackets", func() { + actualContent := "[#img-foobar" + + It("cannot be an attribute", func() { + expectError(GinkgoT(), actualContent, parser.Entrypoint("ElementAttribute")) + }) + + It("is an inline content", func() { + expectedDocument := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{ + Content: "[#img-foobar", + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("InlineContent")) + }) + }) + }) + }) + Context("element title", func() { + + Context("valid syntax", func() { + + It("element title", func() { + actualContent := ".a title" + expectedDocument := &types.ElementTitle{Value: "a title"} + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("ElementAttribute")) + }) + }) + + Context("invalid syntax", func() { + Context("extra space after dot", func() { + + actualContent := ". a title" + It("cannot be an attribute", func() { + expectError(GinkgoT(), actualContent, parser.Entrypoint("ElementAttribute")) + }) + + It("is an inline content", func() { + expectedDocument := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{ + Content: ". a title", + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("InlineContent")) + }) + }) + + Context("not a dot", func() { + actualContent := "!a title" + + It("cannot be an attribute", func() { + expectError(GinkgoT(), actualContent, parser.Entrypoint("ElementAttribute")) + }) + + It("is an inline content", func() { + expectedDocument := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{ + Content: "!a title", + }, + }, + } + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("InlineContent")) + }) + }) + }) + }) +}) diff --git a/parser/external_link_test.go b/parser/external_link_test.go index 93429366..b7683126 100644 --- a/parser/external_link_test.go +++ b/parser/external_link_test.go @@ -1,6 +1,7 @@ package parser_test import ( + "github.com/bytesparadise/libasciidoc/parser" "github.com/bytesparadise/libasciidoc/types" . "github.com/onsi/ginkgo" ) @@ -9,69 +10,42 @@ var _ = Describe("External Links", func() { It("external link", func() { actualContent := "a link to https://foo.bar" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a link to "}, - &types.ExternalLink{ - URL: "https://foo.bar", - }, - }, - }, - }, + expectedDocument := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a link to "}, + &types.ExternalLink{ + URL: "https://foo.bar", }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("InlineContent")) }) It("external link with empty text", func() { actualContent := "a link to https://foo.bar[]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a link to "}, - &types.ExternalLink{ - URL: "https://foo.bar", - Text: "", - }, - }, - }, - }, + expectedDocument := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a link to "}, + &types.ExternalLink{ + URL: "https://foo.bar", + Text: "", }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("InlineContent")) }) It("external link with text", func() { actualContent := "a link to mailto:foo@bar[the foo@bar email]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a link to "}, - &types.ExternalLink{ - URL: "mailto:foo@bar", - Text: "the foo@bar email", - }, - }, - }, - }, + expectedDocument := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a link to "}, + &types.ExternalLink{ + URL: "mailto:foo@bar", + Text: "the foo@bar email", }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("InlineContent")) }) }) diff --git a/parser/frontmatter_test.go b/parser/frontmatter_test.go index d17ce98e..53c25f0d 100644 --- a/parser/frontmatter_test.go +++ b/parser/frontmatter_test.go @@ -20,6 +20,7 @@ first paragraph` "title": "a title", // TODO: convert `title` attribute from front-matter into `doctitle` here ? "author": "Xavier", }, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ @@ -41,7 +42,8 @@ first paragraph` first paragraph` expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ diff --git a/parser/image_test.go b/parser/image_test.go index 829e65c6..baf5aa1b 100644 --- a/parser/image_test.go +++ b/parser/image_test.go @@ -1,6 +1,7 @@ package parser_test import ( + "github.com/bytesparadise/libasciidoc/parser" "github.com/bytesparadise/libasciidoc/types" . "github.com/onsi/ginkgo" ) @@ -11,104 +12,73 @@ var _ = Describe("Images", func() { It("block image with empty alt", func() { actualContent := "image::images/foo.png[]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.ImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, + expectedDocument := &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("BlockImage")) }) It("block image with empty alt and trailing spaces", func() { actualContent := "image::images/foo.png[] \t\t " - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.ImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, + expectedDocument := &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("BlockImage")) }) It("block image with line return", func() { // line return here is not considered as a blank line actualContent := `image::images/foo.png[] ` - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.ImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, + expectedDocument := &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("BlockImage")) }) It("block image with 1 empty blank line", func() { // here, there's a real blank line with some spaces actualContent := `image::images/foo.png[] ` - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.ImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, + expectedDocument := &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("BlockImage")) }) It("block image with 2 blank lines with spaces and tabs", func() { actualContent := `image::images/foo.png[] - ` - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.ImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, + expectedDocument := &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("BlockImage")) }) It("block image with alt", func() { actualContent := "image::images/foo.png[the foo.png image]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.ImageMacro{ - Path: "images/foo.png", - Alt: "the foo.png image", - }, - }, + expectedDocument := &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "the foo.png image", }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("BlockImage")) }) It("block image with dimensions and i d link title meta", func() { @@ -118,48 +88,38 @@ var _ = Describe("Images", func() { "image::images/foo.png[the foo.png image, 600, 400]" width := "600" height := "400" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.BlockImage{ - Macro: types.ImageMacro{ - Path: "images/foo.png", - Alt: "the foo.png image", - Width: &width, - Height: &height, - }, - ID: &types.ElementID{Value: "img-foobar"}, - Title: &types.ElementTitle{Value: "A title to foobar"}, - Link: &types.ElementLink{Path: "http://foo.bar"}, - }, + expectedDocument := &types.BlockImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "the foo.png image", + Width: &width, + Height: &height, }, + ID: &types.ElementID{Value: "img-foobar"}, + Title: &types.ElementTitle{Value: "A title to foobar"}, + Link: &types.ElementLink{Path: "http://foo.bar"}, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("BlockImage")) }) }) Context("Errors", func() { It("block image appending inline content", func() { actualContent := "a paragraph\nimage::images/foo.png[]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a paragraph"}, - }, - }, - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "image::images/foo.png[]"}, - }, - }, + expectedDocument := &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a paragraph"}, + }, + }, + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "image::images/foo.png[]"}, }, }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("Paragraph")) }) }) }) @@ -169,132 +129,91 @@ var _ = Describe("Images", func() { It("inline image with empty alt", func() { actualContent := "image:images/foo.png[]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.InlineImage{ - Macro: types.ImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, - }, - }, + expectedDocument := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.InlineImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", }, }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("InlineContent")) }) It("inline image with empty alt and trailing spaces", func() { actualContent := "image:images/foo.png[] \t\t " - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.InlineImage{ - Macro: types.ImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, - &types.StringElement{ - Content: " \t\t ", - }, - }, - }, + expectedDocument := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.InlineImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", }, }, + &types.StringElement{ + Content: " \t\t ", + }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("InlineContent")) }) It("inline image surrounded with test", func() { actualContent := "a foo image:images/foo.png[] bar..." - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{ - Content: "a foo ", - }, - &types.InlineImage{ - Macro: types.ImageMacro{ - Path: "images/foo.png", - Alt: "foo", - }, - }, - &types.StringElement{ - Content: " bar...", - }, - }, - }, + expectedDocument := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{ + Content: "a foo ", + }, + &types.InlineImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "foo", }, }, + &types.StringElement{ + Content: " bar...", + }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("InlineContent")) }) It("inline image with alt", func() { actualContent := "image:images/foo.png[the foo.png image]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.InlineImage{ - Macro: types.ImageMacro{ - Path: "images/foo.png", - Alt: "the foo.png image", - }, - }, - }, - }, + expectedDocument := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.InlineImage{ + Macro: types.ImageMacro{ + Path: "images/foo.png", + Alt: "the foo.png image", }, }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("InlineContent")) }) }) Context("Errors", func() { It("inline image appending inline content", func() { actualContent := "a paragraph\nimage::images/foo.png[]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a paragraph"}, - }, - }, - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "image::images/foo.png[]"}, - }, - }, + expectedDocument := &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a paragraph"}, + }, + }, + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "image::images/foo.png[]"}, }, }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("Paragraph")) }) }) }) diff --git a/parser/list_test.go b/parser/list_test.go index 1ea30871..f1334b52 100644 --- a/parser/list_test.go +++ b/parser/list_test.go @@ -1,6 +1,7 @@ package parser_test import ( + "github.com/bytesparadise/libasciidoc/parser" "github.com/bytesparadise/libasciidoc/types" . "github.com/onsi/ginkgo" ) @@ -11,20 +12,15 @@ var _ = Describe("List Items", func() { Context("Valid content", func() { It("1 list with a single item", func() { actualContent := "* a list item" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a list item"}, - }, - }, + expectedDocument := &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a list item"}, }, }, }, @@ -32,26 +28,21 @@ var _ = Describe("List Items", func() { }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("List")) }) It("1 list with an ID and a single item", func() { actualContent := "[#listID]\n" + "* a list item" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.List{ - ID: &types.ElementID{Value: "listID"}, - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a list item"}, - }, - }, + expectedDocument := &types.List{ + ID: &types.ElementID{Value: "listID"}, + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a list item"}, }, }, }, @@ -59,41 +50,36 @@ var _ = Describe("List Items", func() { }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("List")) }) It("1 list with 2 items with stars", func() { actualContent := "* a first item\n" + "* a second item with *bold content*" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a first item"}, - }, - }, + expectedDocument := &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a first item"}, }, }, }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ + }, + }, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a second item with "}, + &types.QuotedText{Kind: types.Bold, Elements: []types.InlineElement{ - &types.StringElement{Content: "a second item with "}, - &types.QuotedText{Kind: types.Bold, - Elements: []types.InlineElement{ - &types.StringElement{Content: "bold content"}, - }, - }, + &types.StringElement{Content: "bold content"}, }, }, }, @@ -103,40 +89,35 @@ var _ = Describe("List Items", func() { }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("List")) }) It("1 list with 2 items with carets", func() { actualContent := "- a first item\n" + "- a second item with *bold content*" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a first item"}, - }, - }, + expectedDocument := &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a first item"}, }, }, }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ + }, + }, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a second item with "}, + &types.QuotedText{Kind: types.Bold, Elements: []types.InlineElement{ - &types.StringElement{Content: "a second item with "}, - &types.QuotedText{Kind: types.Bold, - Elements: []types.InlineElement{ - &types.StringElement{Content: "bold content"}, - }, - }, + &types.StringElement{Content: "bold content"}, }, }, }, @@ -146,42 +127,37 @@ var _ = Describe("List Items", func() { }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("List")) }) It("1 list with 2 items with empty line in-between", func() { // fist line after list item is swallowed actualContent := "* a first item\n" + "\n" + "* a second item with *bold content*" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a first item"}, - }, - }, + expectedDocument := &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a first item"}, }, }, }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ + }, + }, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a second item with "}, + &types.QuotedText{Kind: types.Bold, Elements: []types.InlineElement{ - &types.StringElement{Content: "a second item with "}, - &types.QuotedText{Kind: types.Bold, - Elements: []types.InlineElement{ - &types.StringElement{Content: "bold content"}, - }, - }, + &types.StringElement{Content: "bold content"}, }, }, }, @@ -191,49 +167,44 @@ var _ = Describe("List Items", func() { }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("List")) }) It("1 list with 2 items on multiple lines", func() { actualContent := "* item 1\n" + " on 2 lines.\n" + "* item 2\n" + "on 2 lines, too." - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 1"}, - }, - }, - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: " on 2 lines."}, - }, - }, + expectedDocument := &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 1"}, + }, + }, + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: " on 2 lines."}, }, }, }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 2"}, - }, - }, - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "on 2 lines, too."}, - }, - }, + }, + }, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 2"}, + }, + }, + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "on 2 lines, too."}, }, }, }, @@ -241,7 +212,7 @@ var _ = Describe("List Items", func() { }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("List")) }) It("2 lists with 2 empty lines in-between", func() { // the first blank lines after the first list is swallowed (for the list item) @@ -250,7 +221,8 @@ var _ = Describe("List Items", func() { "\n" + "* an item in the second list" expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.List{ Items: []*types.ListItem{ @@ -286,9 +258,8 @@ var _ = Describe("List Items", func() { }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent) // parse the whole document to get 2 lists }) - }) Context("List of multiple levels", func() { @@ -301,113 +272,108 @@ var _ = Describe("List Items", func() { "** item 1.4\n" + "* item 2\n" + "** item 2.1\n" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 1"}, - }, - }, + expectedDocument := &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 1"}, }, }, - Children: &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 1.1"}, - }, - }, + }, + }, + Children: &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 1.1"}, }, }, }, - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 1.2"}, - }, - }, + }, + }, + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 1.2"}, }, }, - Children: &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 3, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 1.2.1"}, - }, - }, + }, + }, + Children: &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 3, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 1.2.1"}, }, }, }, }, }, }, - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 1.3"}, - }, - }, + }, + }, + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 1.3"}, }, }, }, - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 1.4"}, - }, - }, + }, + }, + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 1.4"}, }, }, }, }, }, }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 2"}, - }, - }, + }, + }, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 2"}, }, }, - Children: &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 2.1"}, - }, - }, + }, + }, + Children: &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 2.1"}, }, }, }, @@ -418,7 +384,7 @@ var _ = Describe("List Items", func() { }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("List")) }) }) @@ -430,76 +396,71 @@ var _ = Describe("List Items", func() { "*** item 1.1.1\n" + "** item 1.2\n" + "* item 2" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 1"}, - }, - }, + expectedDocument := &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 1"}, }, }, - Children: &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 1.1"}, - }, - }, + }, + }, + Children: &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 1.1"}, }, }, - Children: &types.List{ - Items: []*types.ListItem{ - &types.ListItem{ - Level: 3, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 1.1.1"}, - }, - }, + }, + }, + Children: &types.List{ + Items: []*types.ListItem{ + &types.ListItem{ + Level: 3, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 1.1.1"}, }, }, }, }, }, }, - &types.ListItem{ - Level: 2, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 1.2"}, - }, - }, + }, + }, + &types.ListItem{ + Level: 2, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 1.2"}, }, }, }, }, }, }, - &types.ListItem{ - Level: 1, - Content: &types.ListItemContent{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "item 2"}, - }, - }, + }, + }, + &types.ListItem{ + Level: 1, + Content: &types.ListItemContent{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "item 2"}, }, }, }, @@ -507,26 +468,21 @@ var _ = Describe("List Items", func() { }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("List")) }) It("invalid list item", func() { actualContent := "*an invalid list item" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "*an invalid list item"}, - }, - }, + expectedDocument := &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "*an invalid list item"}, }, }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("Paragraph")) }) }) }) diff --git a/parser/literal_block_test.go b/parser/literal_block_test.go index 020ca2ae..1afe9827 100644 --- a/parser/literal_block_test.go +++ b/parser/literal_block_test.go @@ -1,6 +1,7 @@ package parser_test import ( + "github.com/bytesparadise/libasciidoc/parser" "github.com/bytesparadise/libasciidoc/types" . "github.com/onsi/ginkgo" ) @@ -11,29 +12,19 @@ var _ = Describe("Literal Blocks", func() { It("literal block from 1-line paragraph with single space", func() { actualContent := ` some literal content` - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.LiteralBlock{ - Content: " some literal content", - }, - }, + expectedDocument := &types.LiteralBlock{ + Content: " some literal content", } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("LiteralBlock")) }) It("literal block from paragraph with single space on first line", func() { actualContent := ` some literal content on 2 lines.` - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.LiteralBlock{ - Content: " some literal content\non 2 lines.", - }, - }, + expectedDocument := &types.LiteralBlock{ + Content: " some literal content\non 2 lines.", } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("LiteralBlock")) }) It("mixing literal block and paragraph ", func() { @@ -41,7 +32,8 @@ on 2 lines.` a normal paragraph.` expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.LiteralBlock{ Content: " some literal content", @@ -69,7 +61,8 @@ some literal content .... a normal paragraph.` expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.LiteralBlock{ Content: "some literal content", @@ -98,7 +91,8 @@ some literal content a normal paragraph.` expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.LiteralBlock{ Content: "some literal content", diff --git a/parser/meta_elements_test.go b/parser/meta_elements_test.go deleted file mode 100644 index e754db4d..00000000 --- a/parser/meta_elements_test.go +++ /dev/null @@ -1,137 +0,0 @@ -package parser_test - -import ( - "github.com/bytesparadise/libasciidoc/types" - . "github.com/onsi/ginkgo" -) - -var _ = Describe("Meta Elements", func() { - - Context("Element link", func() { - - It("element link alone", func() { - actualContent := "[link=http://foo.bar]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.ElementLink{Path: "http://foo.bar"}, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("element link with spaces", func() { - actualContent := "[ link = http://foo.bar ]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.ElementLink{Path: "http://foo.bar"}, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("element link invalid", func() { - actualContent := "[ link = http://foo.bar" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "[ link = "}, - &types.ExternalLink{URL: "http://foo.bar"}, - }, - }, - }, - }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - }) - - Context("element id", func() { - - It("element id", func() { - actualContent := "[#img-foobar]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.ElementID{Value: "img-foobar"}, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("element id with spaces", func() { - actualContent := "[ #img-foobar ]" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.ElementID{Value: "img-foobar"}, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("element id invalid", func() { - actualContent := "[#img-foobar" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{Elements: []types.InlineElement{&types.StringElement{Content: "[#img-foobar"}}}, - }, - }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - }) - Context("element title", func() { - - It("element title", func() { - actualContent := ".a title" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.ElementTitle{Value: "a title"}, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("element title invalid1", func() { - actualContent := ". a title" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{Elements: []types.InlineElement{&types.StringElement{Content: ". a title"}}}, - }, - }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - - It("element title invalid2", func() { - actualContent := "!a title" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{Elements: []types.InlineElement{&types.StringElement{Content: "!a title"}}}, - }, - }, - }, - } - verify(GinkgoT(), expectedDocument, actualContent) - }) - }) -}) diff --git a/parser/paragraph_test.go b/parser/paragraph_test.go index 15e437b4..77d0f204 100644 --- a/parser/paragraph_test.go +++ b/parser/paragraph_test.go @@ -1,6 +1,7 @@ package parser_test import ( + "github.com/bytesparadise/libasciidoc/parser" "github.com/bytesparadise/libasciidoc/types" . "github.com/onsi/ginkgo" ) @@ -9,87 +10,67 @@ var _ = Describe("Paragraphs", func() { It("paragraph with 1 word", func() { actualContent := "hello" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "hello"}, - }, - }, + expectedDocument := &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "hello"}, }, }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("Paragraph")) }) It("paragraph with few words", func() { actualContent := "a paragraph with some content" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a paragraph with some content"}, - }, - }, + expectedDocument := &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a paragraph with some content"}, }, }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("Paragraph")) }) It("paragraph with bold content", func() { actualContent := "a paragraph with *some bold content*" - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ + expectedDocument := &types.Paragraph{ + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a paragraph with "}, + &types.QuotedText{ + Kind: types.Bold, Elements: []types.InlineElement{ - &types.StringElement{Content: "a paragraph with "}, - &types.QuotedText{ - Kind: types.Bold, - Elements: []types.InlineElement{ - &types.StringElement{Content: "some bold content"}, - }, - }, + &types.StringElement{Content: "some bold content"}, }, }, }, }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("Paragraph")) }) It("paragraph with id and title", func() { actualContent := `[#foo] .a title a paragraph` - expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, - Elements: []types.DocElement{ - &types.Paragraph{ - ID: &types.ElementID{Value: "foo"}, - Title: &types.ElementTitle{Value: "a title"}, - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a paragraph"}, - }, - }, + expectedDocument := &types.Paragraph{ + ID: &types.ElementID{Value: "foo"}, + Title: &types.ElementTitle{Value: "a title"}, + Lines: []*types.InlineContent{ + &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a paragraph"}, }, }, }, } - verify(GinkgoT(), expectedDocument, actualContent) + verify(GinkgoT(), expectedDocument, actualContent, parser.Entrypoint("Paragraph")) }) }) diff --git a/parser/quoted_text_test.go b/parser/quoted_text_test.go index 3c315938..ef9462ca 100644 --- a/parser/quoted_text_test.go +++ b/parser/quoted_text_test.go @@ -207,106 +207,82 @@ var _ = Describe("Quoted Texts", func() { It("inline with bold text", func() { actualContent := "a paragraph with *some bold content*" - expectedResult := &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ + expectedResult := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a paragraph with "}, + &types.QuotedText{ + Kind: types.Bold, Elements: []types.InlineElement{ - &types.StringElement{Content: "a paragraph with "}, - &types.QuotedText{ - Kind: types.Bold, - Elements: []types.InlineElement{ - &types.StringElement{Content: "some bold content"}, - }, - }, + &types.StringElement{Content: "some bold content"}, }, }, }, } - verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("Paragraph")) + verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("InlineContent")) }) It("inline with invalid bold text1", func() { actualContent := "a paragraph with *some bold content" - expectedResult := &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a paragraph with *some bold content"}, - }, - }, + expectedResult := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a paragraph with *some bold content"}, }, } - verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("Paragraph")) + verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("InlineContent")) }) It("inline with invalid bold text2", func() { actualContent := "a paragraph with *some bold content *" - expectedResult := &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a paragraph with *some bold content *"}, - }, - }, + expectedResult := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a paragraph with *some bold content *"}, }, } - verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("Paragraph")) + verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("InlineContent")) }) It("inline with invalid bold text3", func() { actualContent := "a paragraph with * some bold content*" - expectedResult := &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ - Elements: []types.InlineElement{ - &types.StringElement{Content: "a paragraph with * some bold content*"}, - }, - }, + expectedResult := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a paragraph with * some bold content*"}, }, } - verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("Paragraph")) + verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("InlineContent")) }) It("invalid italic text within bold text", func() { actualContent := "some *bold and _italic content _ together*." - expectedResult := &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ + expectedResult := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "some "}, + &types.QuotedText{ + Kind: types.Bold, Elements: []types.InlineElement{ - &types.StringElement{Content: "some "}, - &types.QuotedText{ - Kind: types.Bold, - Elements: []types.InlineElement{ - &types.StringElement{Content: "bold and _italic content _ together"}, - }, - }, - &types.StringElement{Content: "."}, + &types.StringElement{Content: "bold and _italic content _ together"}, }, }, + &types.StringElement{Content: "."}, }, } - verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("Paragraph")) + verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("InlineContent")) }) It("italic text within invalid bold text", func() { actualContent := "some *bold and _italic content_ together *." - expectedResult := &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ + expectedResult := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "some *bold and "}, + &types.QuotedText{ + Kind: types.Italic, Elements: []types.InlineElement{ - &types.StringElement{Content: "some *bold and "}, - &types.QuotedText{ - Kind: types.Italic, - Elements: []types.InlineElement{ - &types.StringElement{Content: "italic content"}, - }, - }, - &types.StringElement{Content: " together *."}, + &types.StringElement{Content: "italic content"}, }, }, + &types.StringElement{Content: " together *."}, }, } - verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("Paragraph")) + verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("InlineContent")) }) }) @@ -314,30 +290,26 @@ var _ = Describe("Quoted Texts", func() { It("italic text within bold text", func() { actualContent := "some *bold and _italic content_ together*." - expectedResult := &types.Paragraph{ - Lines: []*types.InlineContent{ - &types.InlineContent{ + expectedResult := &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "some "}, + &types.QuotedText{ + Kind: types.Bold, Elements: []types.InlineElement{ - &types.StringElement{Content: "some "}, + &types.StringElement{Content: "bold and "}, &types.QuotedText{ - Kind: types.Bold, + Kind: types.Italic, Elements: []types.InlineElement{ - &types.StringElement{Content: "bold and "}, - &types.QuotedText{ - Kind: types.Italic, - Elements: []types.InlineElement{ - &types.StringElement{Content: "italic content"}, - }, - }, - &types.StringElement{Content: " together"}, + &types.StringElement{Content: "italic content"}, }, }, - &types.StringElement{Content: "."}, + &types.StringElement{Content: " together"}, }, }, + &types.StringElement{Content: "."}, }, } - verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("Paragraph")) + verify(GinkgoT(), expectedResult, actualContent, parser.Entrypoint("InlineContent")) }) It("simple-quote bold within simple-quote bold text", func() { diff --git a/parser/section_test.go b/parser/section_test.go index abdfa323..fbc18af3 100644 --- a/parser/section_test.go +++ b/parser/section_test.go @@ -24,7 +24,8 @@ var _ = Describe("Sections", func() { }, }, }, - Elements: []types.DocElement{}, + ElementReferences: map[string]interface{}{}, + Elements: []types.DocElement{}, } verify(GinkgoT(), expectedDocument, actualContent) }) @@ -46,6 +47,7 @@ and a paragraph` }, }, }, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ @@ -65,6 +67,18 @@ and a paragraph` actualContent := `== section 1` expectedDocument := &types.Document{ Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{ + "_section_1": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "section 1"}, + }, + }, + ID: &types.ElementID{ + Value: "_section_1", + }, + }, + }, Elements: []types.DocElement{ &types.Section{ Level: 1, @@ -89,6 +103,22 @@ and a paragraph` actualContent := `== *2 spaces and bold content*` expectedDocument := &types.Document{ Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{ + "__strong_2_spaces_and_bold_content_strong": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.QuotedText{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "2 spaces and bold content"}, + }, + }, + }, + }, + ID: &types.ElementID{ + Value: "__strong_2_spaces_and_bold_content_strong", + }, + }, + }, Elements: []types.DocElement{ &types.Section{ Level: 1, @@ -129,7 +159,20 @@ and a paragraph` Value: "_a_header", }, }, - }, Elements: []types.DocElement{ + }, + ElementReferences: map[string]interface{}{ + "_section_1": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "section 1"}, + }, + }, + ID: &types.ElementID{ + Value: "_section_1", + }, + }, + }, + Elements: []types.DocElement{ &types.Section{ Level: 1, SectionTitle: types.SectionTitle{ @@ -167,7 +210,20 @@ a short preamble Value: "_a_header", }, }, - }, Elements: []types.DocElement{ + }, + ElementReferences: map[string]interface{}{ + "_section_1": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "section 1"}, + }, + }, + ID: &types.ElementID{ + Value: "_section_1", + }, + }, + }, + Elements: []types.DocElement{ &types.Preamble{ Elements: []types.DocElement{ &types.Paragraph{ @@ -217,6 +273,18 @@ a short preamble }, }, }, + ElementReferences: map[string]interface{}{ + "_section_2": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "section 2"}, + }, + }, + ID: &types.ElementID{ + Value: "_section_2", + }, + }, + }, Elements: []types.DocElement{ &types.Section{ Level: 2, @@ -242,6 +310,18 @@ a short preamble and a paragraph` expectedDocument := &types.Document{ Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{ + "_a_title": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a title"}, + }, + }, + ID: &types.ElementID{ + Value: "_a_title", + }, + }, + }, Elements: []types.DocElement{ &types.Section{ Level: 1, @@ -275,6 +355,18 @@ and a paragraph` actualContent := "== a title\n\nand a paragraph" expectedDocument := &types.Document{ Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{ + "_a_title": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a title"}, + }, + }, + ID: &types.ElementID{ + Value: "_a_title", + }, + }, + }, Elements: []types.DocElement{ &types.Section{ Level: 1, @@ -309,6 +401,18 @@ and a paragraph` actualContent := "== a title\n \nand a paragraph" expectedDocument := &types.Document{ Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{ + "_a_title": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "a title"}, + }, + }, + ID: &types.ElementID{ + Value: "_a_title", + }, + }, + }, Elements: []types.DocElement{ &types.Section{ Level: 1, @@ -363,6 +467,38 @@ a paragraph` }, }, }, + ElementReferences: map[string]interface{}{ + "_section_a": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "Section A"}, + }, + }, + ID: &types.ElementID{ + Value: "_section_a", + }, + }, + "_section_a_a": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "Section A.a"}, + }, + }, + ID: &types.ElementID{ + Value: "_section_a_a", + }, + }, + "_section_b": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "Section B"}, + }, + }, + ID: &types.ElementID{ + Value: "_section_b", + }, + }, + }, Elements: []types.DocElement{ &types.Section{ Level: 1, @@ -446,7 +582,8 @@ a paragraph` It("header invalid - missing space", func() { actualContent := "=a header" expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.Paragraph{ Lines: []*types.InlineContent{ @@ -464,7 +601,8 @@ a paragraph` It("header invalid - header space", func() { actualContent := " = a header" expectedDocument := &types.Document{ - Attributes: map[string]interface{}{}, + Attributes: map[string]interface{}{}, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.LiteralBlock{ Content: " = a header", @@ -491,6 +629,7 @@ a paragraph` }, }, }, + ElementReferences: map[string]interface{}{}, Elements: []types.DocElement{ &types.LiteralBlock{ Content: " == section 1", diff --git a/parser/table_of_contents_test.go b/parser/table_of_contents_test.go index 8004bcd2..b9a50ee0 100644 --- a/parser/table_of_contents_test.go +++ b/parser/table_of_contents_test.go @@ -61,6 +61,18 @@ A short preamble "doctitle": doctitleAttribute, "toc": "", }, + ElementReferences: map[string]interface{}{ + "_section_1": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "section 1"}, + }, + }, + ID: &types.ElementID{ + Value: "_section_1", + }, + }, + }, Elements: []types.DocElement{ tableOfContents, preamble, @@ -83,6 +95,18 @@ A short preamble "doctitle": doctitleAttribute, "toc": "preamble", }, + ElementReferences: map[string]interface{}{ + "_section_1": &types.SectionTitle{ + Content: &types.InlineContent{ + Elements: []types.InlineElement{ + &types.StringElement{Content: "section 1"}, + }, + }, + ID: &types.ElementID{ + Value: "_section_1", + }, + }, + }, Elements: []types.DocElement{ preamble, tableOfContents, diff --git a/renderer/html5/cross_reference.go b/renderer/html5/cross_reference.go new file mode 100644 index 00000000..5deac3f9 --- /dev/null +++ b/renderer/html5/cross_reference.go @@ -0,0 +1,48 @@ +package html5 + +import ( + "bytes" + "fmt" + "html/template" + + "github.com/bytesparadise/libasciidoc/renderer" + "github.com/bytesparadise/libasciidoc/types" + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" +) + +var crossReferenceTmpl *template.Template + +// initializes the templates +func init() { + crossReferenceTmpl = newHTMLTemplate("cross reference", `{{ .Content }}`) +} + +func renderCrossReference(ctx *renderer.Context, xref *types.CrossReference) ([]byte, error) { + log.Debugf("rendering cross reference with ID: %s", xref.ID) + result := bytes.NewBuffer(nil) + renderedContentStr := fmt.Sprintf("[%s]", xref.ID) + if target, found := ctx.Document.ElementReferences[xref.ID]; found { + switch t := target.(type) { + case *types.SectionTitle: + renderedContent, err := renderElement(ctx, t.Content) + if err != nil { + return nil, errors.Wrapf(err, "error while rendering sectionTitle content") + } + renderedContentStr = string(renderedContent) + default: + return nil, errors.Errorf("unable to process cross-reference to element of type %T", target) + } + } + err := crossReferenceTmpl.Execute(result, struct { + ID string + Content string + }{ + ID: xref.ID, + Content: renderedContentStr, + }) + if err != nil { + return nil, errors.Wrapf(err, "unable to render cross reference") + } + return result.Bytes(), nil +} diff --git a/renderer/html5/cross_reference_test.go b/renderer/html5/cross_reference_test.go new file mode 100644 index 00000000..875128ab --- /dev/null +++ b/renderer/html5/cross_reference_test.go @@ -0,0 +1,47 @@ +package html5_test + +import . "github.com/onsi/ginkgo" + +var _ = Describe("Cross References", func() { + + Context("Reference to section", func() { + + Context("valid reference", func() { + + It("custom id", func() { + actualContent := `[[thetitle]] +== a title + +with some content linked to <>!` + expected := `
+

a title

+
+
+

with some content linked to a title!

+
+
+
` + verify(GinkgoT(), expected, actualContent) + }) + }) + + Context("invalid reference", func() { + + It("custom id", func() { + actualContent := `[[thetitle]] +== a title + +with some content linked to <>!` + expected := `
+

a title

+
+
+

with some content linked to [thewrongtitle]!

+
+
+
` + verify(GinkgoT(), expected, actualContent) + }) + }) + }) +}) diff --git a/renderer/html5/renderer.go b/renderer/html5/renderer.go index 2d4ee976..33d28f28 100644 --- a/renderer/html5/renderer.go +++ b/renderer/html5/renderer.go @@ -16,22 +16,24 @@ func Render(ctx *renderer.Context, output io.Writer) (map[string]interface{}, er } func renderElement(ctx *renderer.Context, element types.DocElement) ([]byte, error) { - log.Debugf("rendering element of type %T", element) - switch element.(type) { + log.Debugf("rendering element of type `%T`", element) + switch e := element.(type) { case *types.TableOfContentsMacro: - return renderTableOfContent(ctx, element.(*types.TableOfContentsMacro)) + return renderTableOfContent(ctx, e) case *types.Section: - return renderSection(ctx, element.(*types.Section)) + return renderSection(ctx, e) case *types.Preamble: - return renderPreamble(ctx, element.(*types.Preamble)) + return renderPreamble(ctx, e) case *types.List: - return renderList(ctx, element.(*types.List)) + return renderList(ctx, e) case *types.Paragraph: - return renderParagraph(ctx, element.(*types.Paragraph)) + return renderParagraph(ctx, e) + case *types.CrossReference: + return renderCrossReference(ctx, e) case *types.QuotedText: - return renderQuotedText(ctx, element.(*types.QuotedText)) + return renderQuotedText(ctx, e) case *types.Passthrough: - return renderPassthrough(ctx, element.(*types.Passthrough)) + return renderPassthrough(ctx, e) case *types.BlockImage: return renderBlockImage(ctx, element.(*types.BlockImage)) case *types.InlineImage: diff --git a/renderer/html5/section.go b/renderer/html5/section.go index 6468dc4a..cac7344f 100644 --- a/renderer/html5/section.go +++ b/renderer/html5/section.go @@ -67,9 +67,12 @@ func renderSection(ctx *renderer.Context, s *types.Section) ([]byte, error) { log.Debugf("Rendering section level %d", s.Level) renderedSectionTitle, err := renderSectionTitle(ctx, s.Level, s.SectionTitle) if err != nil { - return nil, errors.Wrapf(err, "error while rendering section sectionTitle") + return nil, errors.Wrapf(err, "error while rendering section") } renderedSectionElements, err := renderSectionElements(ctx, s.Elements) + if err != nil { + return nil, errors.Wrapf(err, "error while rendering section") + } result := bytes.NewBuffer(nil) // select the appropriate template for the section var tmpl *template.Template diff --git a/types/document_xrefs.go b/types/document_xrefs.go new file mode 100644 index 00000000..a63e134a --- /dev/null +++ b/types/document_xrefs.go @@ -0,0 +1,40 @@ +package types + +import ( + log "github.com/sirupsen/logrus" +) + +// ElementReferences the element references in the document +type ElementReferences map[string]interface{} + +// ElementReferencesCollector the visitor that traverses the whole document structure in search for elements with an ID +type ElementReferencesCollector struct { + ElementReferences ElementReferences +} + +// NewElementReferencesCollector initializes a new ElementReferencesCollector +func NewElementReferencesCollector() *ElementReferencesCollector { + return &ElementReferencesCollector{ + ElementReferences: ElementReferences{}, + } +} + +// BeforeVisit Implements Visitable#BeforeVisit() +func (c *ElementReferencesCollector) BeforeVisit(element Visitable) error { + return nil +} + +// Visit Implements Visitable#Visit() +func (c *ElementReferencesCollector) Visit(element Visitable) error { + switch e := element.(type) { + case *Section: + log.Debugf("Adding element reference: %v", *e.SectionTitle.ID) + c.ElementReferences[e.SectionTitle.ID.Value] = &e.SectionTitle + } + return nil +} + +// AfterVisit Implements Visitable#AfterVisit() +func (c *ElementReferencesCollector) AfterVisit(element Visitable) error { + return nil +} diff --git a/types/grammar_types.go b/types/grammar_types.go index c32d53cd..4ab1980f 100644 --- a/types/grammar_types.go +++ b/types/grammar_types.go @@ -20,12 +20,12 @@ import ( // DocElement the interface for all document elements type DocElement interface { + // Visitable } // InlineElement the interface for inline elements type InlineElement interface { DocElement - // Visitable } // Visitable the interface for visitable elements @@ -35,9 +35,9 @@ type Visitable interface { // Visitor a visitor that can visit/traverse the DocElement and its children (if applicable) type Visitor interface { - BeforeVisit(interface{}) error - Visit(interface{}) error - AfterVisit(interface{}) error + BeforeVisit(Visitable) error + Visit(Visitable) error + AfterVisit(Visitable) error } // ------------------------------------------ @@ -46,8 +46,9 @@ type Visitor interface { // Document the top-level structure for a document type Document struct { - Attributes DocumentAttributes - Elements []DocElement + Attributes DocumentAttributes + Elements []DocElement + ElementReferences ElementReferences } // NewDocument initializes a new `Document` from the given lines @@ -95,14 +96,23 @@ func NewDocument(frontmatter, header interface{}, blocks []interface{}) (*Docume log.Warnf("invalid value for 'toc' attribute: '%s'", attrValue) } - } } } + + c := NewElementReferencesCollector() + for _, e := range elements { + if v, ok := e.(Visitable); ok { + v.Accept(c) + } + } document := &Document{ - Attributes: attributes, - Elements: elements, + Attributes: attributes, + Elements: elements, + ElementReferences: c.ElementReferences, } + + // visit all elements in the `AST` to retrieve their reference (ie, their ElementID if they have any) return document, nil } @@ -191,7 +201,7 @@ func NewDocumentAuthor(namePart1, namePart2, namePart3, emailAddress interface{} var part1, part2, part3, email *string var err error if namePart1 != nil { - part1, err = Stringify(namePart1.([]interface{}), + part1, err = stringify(namePart1.([]interface{}), func(s string) (string, error) { return strings.TrimSpace(s), nil }, @@ -204,7 +214,7 @@ func NewDocumentAuthor(namePart1, namePart2, namePart3, emailAddress interface{} } } if namePart2 != nil { - part2, err = Stringify(namePart2.([]interface{}), + part2, err = stringify(namePart2.([]interface{}), func(s string) (string, error) { return strings.TrimSpace(s), nil }, @@ -217,7 +227,7 @@ func NewDocumentAuthor(namePart1, namePart2, namePart3, emailAddress interface{} } } if namePart3 != nil { - part3, err = Stringify(namePart3.([]interface{}), + part3, err = stringify(namePart3.([]interface{}), func(s string) (string, error) { return strings.TrimSpace(s), nil }, @@ -230,7 +240,7 @@ func NewDocumentAuthor(namePart1, namePart2, namePart3, emailAddress interface{} } } if emailAddress != nil { - email, err = Stringify(emailAddress.([]interface{}), + email, err = stringify(emailAddress.([]interface{}), func(s string) (string, error) { return strings.TrimPrefix(s, "<"), nil }, func(s string) (string, error) { @@ -300,7 +310,7 @@ func NewDocumentRevision(revnumber, revdate, revremark interface{}) (*DocumentRe var number, date, remark *string var err error if revnumber != nil { - number, err = Stringify(revnumber.([]interface{}), + number, err = stringify(revnumber.([]interface{}), func(s string) (string, error) { return strings.TrimPrefix(s, "v"), nil }, func(s string) (string, error) { @@ -314,7 +324,7 @@ func NewDocumentRevision(revnumber, revdate, revremark interface{}) (*DocumentRe } if revdate != nil { // stringify, then remove the "," prefix and trim spaces - date, err = Stringify(revdate.([]interface{}), func(s string) (string, error) { + date, err = stringify(revdate.([]interface{}), func(s string) (string, error) { return strings.TrimSpace(s), nil }) if err != nil { @@ -327,7 +337,7 @@ func NewDocumentRevision(revnumber, revdate, revremark interface{}) (*DocumentRe } if revremark != nil { // then we need to strip the heading "," and spaces - remark, err = Stringify(revremark.([]interface{}), + remark, err = stringify(revremark.([]interface{}), func(s string) (string, error) { return strings.TrimPrefix(s, ":"), nil }, func(s string) (string, error) { @@ -379,14 +389,14 @@ type DocumentAttributeDeclaration struct { // NewDocumentAttributeDeclaration initializes a new DocumentAttributeDeclaration func NewDocumentAttributeDeclaration(name []interface{}, value []interface{}) (*DocumentAttributeDeclaration, error) { - attrName, err := Stringify(name, + attrName, err := stringify(name, func(s string) (string, error) { return strings.TrimSpace(s), nil }) if err != nil { return nil, errors.Wrapf(err, "error while initializing a DocumentAttributeDeclaration") } - attrValue, err := Stringify(value, + attrValue, err := stringify(value, func(s string) (string, error) { return strings.TrimSpace(s), nil }) @@ -407,7 +417,7 @@ type DocumentAttributeReset struct { // NewDocumentAttributeReset initializes a new Document Attribute Resets. func NewDocumentAttributeReset(name []interface{}) (*DocumentAttributeReset, error) { - attrName, err := Stringify(name) + attrName, err := stringify(name) if err != nil { return nil, errors.Wrapf(err, "error while initializing a DocumentAttributeReset") } @@ -422,7 +432,7 @@ type DocumentAttributeSubstitution struct { // NewDocumentAttributeSubstitution initializes a new Document Attribute Substitutions func NewDocumentAttributeSubstitution(name []interface{}) (*DocumentAttributeSubstitution, error) { - attrName, err := Stringify(name) + attrName, err := stringify(name) if err != nil { return nil, errors.Wrapf(err, "error while initializing a DocumentAttributeSubstitution") } @@ -501,6 +511,32 @@ func NewSection(level int, sectionTitle *SectionTitle, blocks []interface{}) (*S }, nil } +// Accept implements Visitable#Accept(Visitor) +func (s *Section) Accept(v Visitor) error { + err := v.BeforeVisit(s) + if err != nil { + return errors.Wrapf(err, "error while pre-visiting section") + } + err = v.Visit(s) + if err != nil { + return errors.Wrapf(err, "error while visiting section") + } + for _, element := range s.Elements { + if visitable, ok := element.(Visitable); ok { + err = visitable.Accept(v) + if err != nil { + return errors.Wrapf(err, "error while visiting section element") + } + } + + } + err = v.AfterVisit(s) + if err != nil { + return errors.Wrapf(err, "error while post-visiting section") + } + return nil +} + // ------------------------------------------ // SectionTitle // ------------------------------------------ @@ -710,6 +746,21 @@ func (c *InlineContent) Accept(v Visitor) error { return nil } +// ------------------------------------------ +// Cross References +// ------------------------------------------ + +// CrossReference the struct for Cross References +type CrossReference struct { + ID string +} + +// NewCrossReference initializes a new `CrossReference` from the given ID +func NewCrossReference(id string) (*CrossReference, error) { + log.Debugf("Initializing a new CrossReference with ID=%s", id) + return &CrossReference{ID: id}, nil +} + // ------------------------------------------ // Images // ------------------------------------------ @@ -812,7 +863,7 @@ type DelimitedBlock struct { // NewDelimitedBlock initializes a new `DelimitedBlock` of the given kind with the given content func NewDelimitedBlock(kind DelimitedBlockKind, content []interface{}) (*DelimitedBlock, error) { - blockContent, err := Stringify(content, + blockContent, err := stringify(content, // remove "\n" or "\r\n", depending on the OS. func(s string) (string, error) { return strings.TrimSuffix(s, "\n"), nil @@ -843,7 +894,7 @@ type LiteralBlock struct { func NewLiteralBlock(spaces, content []interface{}) (*LiteralBlock, error) { // concatenates the spaces with the actual content in a single 'stringified' value // log.Debugf("Initializing a new LiteralBlock with spaces='%v' and content=`%v`", spaces, content) - c, err := Stringify(append(spaces, content...)) + c, err := stringify(append(spaces, content...)) if err != nil { return nil, errors.Wrapf(err, "unable to initialize a new literal block") } @@ -894,25 +945,37 @@ type ElementID struct { Value string } -// NewElementID initializes a new `ElementID` from the given path +// NewElementID initializes a new `ElementID` from the given ID func NewElementID(id string) (*ElementID, error) { - log.Debugf("Initializing a new ElementID with value=%s", id) + log.Debugf("Initializing a new ElementID with ID=%s", id) return &ElementID{Value: id}, nil } -// ElementTitle the structure for element IDs +// ElementTitle the structure for element Titles type ElementTitle struct { Value string } -// NewElementTitle initializes a new `ElementTitle` from the given content -func NewElementTitle(content []interface{}) (*ElementTitle, error) { - c, err := Stringify(content) +// NewElementTitle initializes a new `ElementTitle` from the given value +func NewElementTitle(value []interface{}) (*ElementTitle, error) { + v, err := stringify(value) if err != nil { return nil, errors.Wrapf(err, "failed to initialize a new ElementTitle") } - log.Debugf("Initializing a new ElementTitle with content=%s", *c) - return &ElementTitle{Value: *c}, nil + log.Debugf("Initializing a new ElementTitle with content=%s", *v) + return &ElementTitle{Value: *v}, nil +} + +// InvalidElementAttribute the struct for invalid element attributes +type InvalidElementAttribute struct { + Value string +} + +// NewInvalidElementAttribute initializes a new `InvalidElementAttribute` from the given text +func NewInvalidElementAttribute(text []byte) (*InvalidElementAttribute, error) { + value := string(text) + log.Debugf("Initializing a new InvalidElementAttribute with text=%s", value) + return &InvalidElementAttribute{Value: value}, nil } // ------------------------------------------ @@ -1012,7 +1075,7 @@ func (t *QuotedText) Accept(v Visitor) error { // NewEscapedQuotedText returns a new InlineContent where the nested elements are preserved (ie, substituted as expected) func NewEscapedQuotedText(backslashes []interface{}, punctuation string, content []interface{}) (*InlineContent, error) { - backslashesStr, err := Stringify(backslashes, + backslashesStr, err := stringify(backslashes, func(s string) (string, error) { // remove the number of back-slashes that match the length of the punctuation. Eg: `\*` or `\\**`, but keep extra back-slashes if len(s) > len(punctuation) { @@ -1088,11 +1151,11 @@ type ExternalLink struct { // NewExternalLink initializes a new `ExternalLink` func NewExternalLink(url, text []interface{}) (*ExternalLink, error) { - urlStr, err := Stringify(url) + urlStr, err := stringify(url) if err != nil { return nil, errors.Wrapf(err, "failed to initialize a new ExternalLink element") } - textStr, err := Stringify(text, // remove "\n" or "\r\n", depending on the OS. + textStr, err := stringify(text, // remove "\n" or "\r\n", depending on the OS. // remove heading "[" and traingin "]" func(s string) (string, error) { return strings.TrimPrefix(s, "["), nil diff --git a/types/grammar_types_utils.go b/types/grammar_types_utils.go index fbb4e86c..4e474264 100644 --- a/types/grammar_types_utils.go +++ b/types/grammar_types_utils.go @@ -2,8 +2,6 @@ package types import ( "bytes" - "strings" - "unicode" "github.com/pkg/errors" log "github.com/sirupsen/logrus" @@ -109,12 +107,12 @@ func appendBuffer(elements []interface{}, buff *bytes.Buffer) ([]interface{}, *b return elements, buff } -// StringifyOption a function to apply on the result of the `Stringify` function below, before returning -type StringifyOption func(s string) (string, error) +// stringifyOption a function to apply on the result of the `stringify` function below, before returning +type stringifyOption func(s string) (string, error) -//Stringify convert the given elements into a string, then applies the optional `funcs` to convert the string before returning it. +// stringify convert the given elements into a string, then applies the optional `funcs` to convert the string before returning it. // These StringifyFuncs can be used to trim the content, for example -func Stringify(elements []interface{}, options ...StringifyOption) (*string, error) { +func stringify(elements []interface{}, options ...stringifyOption) (*string, error) { mergedElements := merge(elements) b := make([]byte, 0) buff := bytes.NewBuffer(b) @@ -123,7 +121,7 @@ func Stringify(elements []interface{}, options ...StringifyOption) (*string, err case *StringElement: buff.WriteString(element.Content) case []interface{}: - stringifiedElement, err := Stringify(element) + stringifiedElement, err := stringify(element) if err != nil { // no need to wrap the error again in the same function return nil, err @@ -145,124 +143,3 @@ func Stringify(elements []interface{}, options ...StringifyOption) (*string, err // log.Debugf("stringified %v -> '%s' (%v characters)", elements, result, len(result)) return &result, nil } - -//NormalizationFunc a function that is used to normalize a string. -type NormalizationFunc func(string) ([]byte, error) - -func isMn(r rune) bool { - return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks -} - -// NewReplaceNonAlphanumericsFunc replaces all non alphanumerical characters and remove (accents) -// in the given 'source' with the given 'replacement'. -func NewReplaceNonAlphanumericsFunc(replacement string) NormalizationFunc { - return func(source string) ([]byte, error) { - buf := bytes.NewBuffer(nil) - lastCharIsSpace := false - for _, r := range strings.TrimLeft(source, " ") { // ignore header spaces - if unicode.Is(unicode.Letter, r) || unicode.Is(unicode.Number, r) { - _, err := buf.WriteString(strings.ToLower(string(r))) - if err != nil { - return nil, errors.Wrapf(err, "unable to normalize value") - } - lastCharIsSpace = false - } else if !lastCharIsSpace && (unicode.Is(unicode.Space, r) || unicode.Is(unicode.Punct, r)) { - _, err := buf.WriteString(replacement) - if err != nil { - return nil, errors.Wrapf(err, "unable to normalize value") - } - lastCharIsSpace = true - } - } - result := strings.TrimSuffix(buf.String(), replacement) - return []byte(result), nil - } -} - -func ReplaceNonAlphanumerics(source *InlineContent, replacement string) (*string, error) { - v := NewReplaceNonAlphanumericsVisitor() - s := *source - err := s.Accept(v) - if err != nil { - return nil, err - } - result := v.NormalizedContent() - return &result, nil -} - -//ReplaceNonAlphanumericsVisitor a visitor that builds a string representation of the visited elements, -// in which all non-alphanumeric characters have been replaced with a "_" -type ReplaceNonAlphanumericsVisitor struct { - buf bytes.Buffer - normalize NormalizationFunc -} - -func NewReplaceNonAlphanumericsVisitor() *ReplaceNonAlphanumericsVisitor { - buf := bytes.NewBuffer(nil) - return &ReplaceNonAlphanumericsVisitor{ - buf: *buf, - normalize: NewReplaceNonAlphanumericsFunc("_"), - } -} - -func (v *ReplaceNonAlphanumericsVisitor) Visit(element interface{}) error { - switch element := element.(type) { - case *InlineContent: - // log.Debugf("Prefixing with '_' while processing '%T'", element) - v.buf.WriteString("_") - case *StringElement: - normalized, err := v.normalize(element.Content) - if err != nil { - return errors.Wrapf(err, "error while normalizing String Element") - } - v.buf.Write(normalized) - default: - // ignore - } - return nil -} - -func (v *ReplaceNonAlphanumericsVisitor) BeforeVisit(element interface{}) error { - // log.Debugf("Before visiting element of type '%T'...", element) - switch element := element.(type) { - case *QuotedText: - // log.Debugf("Before visiting quoted element...") - switch element.Kind { - case Bold: - v.buf.WriteString("_strong_") - case Italic: - v.buf.WriteString("_italic_") - case Monospace: - v.buf.WriteString("_monospace_") - default: - return errors.Errorf("unsupported kind of quoted text: %d", element.Kind) - } - default: - // ignore - } - return nil -} - -func (v *ReplaceNonAlphanumericsVisitor) AfterVisit(element interface{}) error { - switch element := element.(type) { - case *QuotedText: - switch element.Kind { - case Bold: - v.buf.WriteString("_strong") - case Italic: - v.buf.WriteString("_italic") - case Monospace: - v.buf.WriteString("_monospace") - default: - return errors.Errorf("unsupported kind of quoted text: %d", element.Kind) - } - default: - // ignore - } - return nil -} - -func (v *ReplaceNonAlphanumericsVisitor) NormalizedContent() string { - result := v.buf.String() - return result -} diff --git a/types/non_alphanumerics_replacement.go b/types/non_alphanumerics_replacement.go new file mode 100644 index 00000000..17d8a076 --- /dev/null +++ b/types/non_alphanumerics_replacement.go @@ -0,0 +1,130 @@ +package types + +import ( + "bytes" + "strings" + "unicode" + + "github.com/pkg/errors" +) + +//NormalizationFunc a function that is used to normalize a string. +type NormalizationFunc func(string) ([]byte, error) + +func isMn(r rune) bool { + return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks +} + +// NewReplaceNonAlphanumericsFunc replaces all non alphanumerical characters and remove (accents) +// in the given 'source' with the given 'replacement'. +func NewReplaceNonAlphanumericsFunc(replacement string) NormalizationFunc { + return func(source string) ([]byte, error) { + buf := bytes.NewBuffer(nil) + lastCharIsSpace := false + for _, r := range strings.TrimLeft(source, " ") { // ignore header spaces + if unicode.Is(unicode.Letter, r) || unicode.Is(unicode.Number, r) { + _, err := buf.WriteString(strings.ToLower(string(r))) + if err != nil { + return nil, errors.Wrapf(err, "unable to normalize value") + } + lastCharIsSpace = false + } else if !lastCharIsSpace && (unicode.Is(unicode.Space, r) || unicode.Is(unicode.Punct, r)) { + _, err := buf.WriteString(replacement) + if err != nil { + return nil, errors.Wrapf(err, "unable to normalize value") + } + lastCharIsSpace = true + } + } + result := strings.TrimSuffix(buf.String(), replacement) + return []byte(result), nil + } +} + +func ReplaceNonAlphanumerics(source *InlineContent, replacement string) (*string, error) { + v := NewReplaceNonAlphanumericsVisitor() + s := *source + err := s.Accept(v) + if err != nil { + return nil, err + } + result := v.NormalizedContent() + return &result, nil +} + +//ReplaceNonAlphanumericsVisitor a visitor that builds a string representation of the visited elements, +// in which all non-alphanumeric characters have been replaced with a "_" +type ReplaceNonAlphanumericsVisitor struct { + buf bytes.Buffer + normalize NormalizationFunc +} + +func NewReplaceNonAlphanumericsVisitor() *ReplaceNonAlphanumericsVisitor { + buf := bytes.NewBuffer(nil) + return &ReplaceNonAlphanumericsVisitor{ + buf: *buf, + normalize: NewReplaceNonAlphanumericsFunc("_"), + } +} + +func (v *ReplaceNonAlphanumericsVisitor) Visit(element Visitable) error { + switch element := element.(type) { + case *InlineContent: + // log.Debugf("Prefixing with '_' while processing '%T'", element) + v.buf.WriteString("_") + case *StringElement: + normalized, err := v.normalize(element.Content) + if err != nil { + return errors.Wrapf(err, "error while normalizing String Element") + } + v.buf.Write(normalized) + default: + // ignore + } + return nil +} + +func (v *ReplaceNonAlphanumericsVisitor) BeforeVisit(element Visitable) error { + // log.Debugf("Before visiting element of type '%T'...", element) + switch element := element.(type) { + case *QuotedText: + // log.Debugf("Before visiting quoted element...") + switch element.Kind { + case Bold: + v.buf.WriteString("_strong_") + case Italic: + v.buf.WriteString("_italic_") + case Monospace: + v.buf.WriteString("_monospace_") + default: + return errors.Errorf("unsupported kind of quoted text: %d", element.Kind) + } + default: + // ignore + } + return nil +} + +func (v *ReplaceNonAlphanumericsVisitor) AfterVisit(element Visitable) error { + switch element := element.(type) { + case *QuotedText: + switch element.Kind { + case Bold: + v.buf.WriteString("_strong") + case Italic: + v.buf.WriteString("_italic") + case Monospace: + v.buf.WriteString("_monospace") + default: + return errors.Errorf("unsupported kind of quoted text: %d", element.Kind) + } + default: + // ignore + } + return nil +} + +func (v *ReplaceNonAlphanumericsVisitor) NormalizedContent() string { + result := v.buf.String() + return result +}